<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="牛客论坛项目实战, ForageAhead">
    <meta name="description" content="最怕你一生碌碌无为，还安慰自己平凡可贵！">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>牛客论坛项目实战 | ForageAhead</title>
    <link rel="icon" type="image/png" href="/hexo-blog/favicon.png">

    <link rel="stylesheet" type="text/css" href="/hexo-blog/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/hexo-blog/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/hexo-blog/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/hexo-blog/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/hexo-blog/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/hexo-blog/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/hexo-blog/css/my.css">

    <script src="/hexo-blog/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 5.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
<link rel="alternate" href="/hexo-blog/atom.xml" title="ForageAhead" type="application/atom+xml">
</head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/hexo-blog/" class="waves-effect waves-light">
                    
                    <img src="/hexo-blog/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">ForageAhead</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/hexo-blog/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/hexo-blog/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">ForageAhead</div>
        <div class="logo-desc">
            
            最怕你一生碌碌无为，还安慰自己平凡可贵！
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/hexo-blog/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/CodeFarmer1999" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/CodeFarmer1999" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    
<script src="/hexo-blog/libs/cryptojs/crypto-js.min.js"></script>
<script>
    (function() {
        let pwd = '';
        if (pwd && pwd.length > 0) {
            if (pwd !== CryptoJS.SHA256(prompt('请输入访问本文章的密码')).toString(CryptoJS.enc.Hex)) {
                alert('密码错误，将返回主页！');
                location.href = '/hexo-blog/';
            }
        }
    })();
</script>




<div class="bg-cover pd-header post-cover" style="background-image: url('/hexo-blog/medias/featureimages/23.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">牛客论坛项目实战</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/hexo-blog/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/hexo-blog/tags/SpringBoot/">
                                <span class="chip bg-color">SpringBoot</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/hexo-blog/categories/%E5%90%8E%E7%AB%AF/" class="post-category">
                                后端
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-02-05
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>更新日期:&nbsp;&nbsp;
                    2021-02-05
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    13.1k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    63 分
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>阅读次数:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">

        
        <!-- 是否加载使用自带的 prismjs. -->
        <link rel="stylesheet" href="/hexo-blog/libs/prism/prism.css">
        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="Community-论坛项目"><a href="#Community-论坛项目" class="headerlink" title="Community 论坛项目"></a>Community 论坛项目</h1><blockquote>
<p>转载请附带原文链接：</p>
</blockquote>
<h2 id="1-环境搭建与技术栈说明"><a href="#1-环境搭建与技术栈说明" class="headerlink" title="1. 环境搭建与技术栈说明"></a>1. 环境搭建与技术栈说明</h2><h3 id="1-0-项目架构图"><a href="#1-0-项目架构图" class="headerlink" title="1.0 项目架构图"></a>1.0 项目架构图</h3><p><img src="https://img-blog.csdnimg.cn/20201204163028259.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="1-1-技术要求"><a href="#1-1-技术要求" class="headerlink" title="1.1 技术要求"></a>1.1 技术要求</h3><ul>
<li>熟悉快速开发框架：<strong>SpringBoot2.3.x</strong>  整合 <strong>SpringMVC + Mybatis</strong></li>
<li>熟悉版本控制：<strong>Maven3.6.X + Git</strong></li>
<li>数据库以及文件存储：<strong>MySQL</strong> + <strong>文件存储阿里云OSS</strong> </li>
<li>熟悉页面模板引擎：<strong>Thymleaf3.x</strong></li>
<li>第三方工具：<strong>网页长图生成工具Wkhtmltopdf</strong>  + <strong>验证码生成工具kaptcha</strong></li>
<li>中间件：<strong>分布式缓存Redis</strong> + <strong>全文检索ElasticSearch</strong> + <strong>Kafka</strong> + <strong>本地缓存Caffeine</strong> </li>
<li>权限框架：<strong>Spring Securtiy +  Spring Actuator</strong></li>
<li>熟悉前端：<strong>Ajax + Vue + BootStrap + HTML + jQuery</strong></li>
</ul>
<h3 id="1-2-环境搭建"><a href="#1-2-环境搭建" class="headerlink" title="1.2 环境搭建"></a>1.2 环境搭建</h3><h4 id="初始化SpringBoot项目："><a href="#初始化SpringBoot项目：" class="headerlink" title="初始化SpringBoot项目："></a>初始化SpringBoot项目：</h4><p><img src="https://img-blog.csdnimg.cn/20201120221656485.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h4 id="初始化后的pom-xml："><a href="#初始化后的pom-xml：" class="headerlink" title="初始化后的pom.xml："></a>初始化后的pom.xml：</h4><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token comment">&lt;!--thymleaf--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-thymeleaf<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--web--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-web<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--mybatis--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.mybatis.spring.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mybatis-spring-boot-starter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>2.1.4<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--热部署--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-devtools<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>runtime<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>optional</span><span class="token punctuation">&gt;</span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>optional</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--mysql--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>mysql<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mysql-connector-java<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>runtime<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--lombok--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.projectlombok<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>lombok<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>optional</span><span class="token punctuation">&gt;</span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>optional</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--test--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>exclusions</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>exclusion</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.junit.vintage<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>junit-vintage-engine<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>exclusion</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>exclusions</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="项目初始结构："><a href="#项目初始结构：" class="headerlink" title="项目初始结构："></a>项目初始结构：</h4><p><img src="https://img-blog.csdnimg.cn/20201124083836256.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h3 id="1-3-数据库设计"><a href="#1-3-数据库设计" class="headerlink" title="1.3 数据库设计"></a>1.3 数据库设计</h3><h4 id="数据库表sql"><a href="#数据库表sql" class="headerlink" title="数据库表sql"></a>数据库表sql</h4><pre class="line-numbers language-sql" data-language="sql"><code class="language-sql"><span class="token keyword">SET</span> NAMES utf8 <span class="token punctuation">;</span>
<span class="token comment">--</span>
<span class="token comment">-- Table structure for table `comment`</span>
<span class="token comment">--</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> <span class="token punctuation">`</span><span class="token keyword">comment</span><span class="token punctuation">`</span><span class="token punctuation">;</span>
 <span class="token keyword">SET</span> character_set_client <span class="token operator">=</span> utf8mb4 <span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span><span class="token keyword">comment</span><span class="token punctuation">`</span> <span class="token punctuation">(</span>
  <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>user_id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>entity_type<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>entity_id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>target_id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>content<span class="token punctuation">`</span> <span class="token keyword">text</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">status</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>create_time<span class="token punctuation">`</span> <span class="token keyword">timestamp</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_user_id<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>user_id<span class="token punctuation">`</span><span class="token punctuation">)</span> <span class="token comment">/*!80000 INVISIBLE */</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_entity_id<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>entity_id<span class="token punctuation">`</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span> <span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span> <span class="token keyword">DEFAULT</span> <span class="token keyword">CHARSET</span><span class="token operator">=</span>utf8<span class="token punctuation">;</span>
<span class="token comment">--</span>
<span class="token comment">-- Table structure for table `discuss_post`</span>
<span class="token comment">--</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> <span class="token punctuation">`</span>discuss_post<span class="token punctuation">`</span><span class="token punctuation">;</span>
 <span class="token keyword">SET</span> character_set_client <span class="token operator">=</span> utf8mb4 <span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span>discuss_post<span class="token punctuation">`</span> <span class="token punctuation">(</span>
  <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>user_id<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">45</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>title<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>content<span class="token punctuation">`</span> <span class="token keyword">text</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">type</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span> <span class="token keyword">COMMENT</span> <span class="token string">'0-普通; 1-置顶;'</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">status</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span> <span class="token keyword">COMMENT</span> <span class="token string">'0-正常; 1-精华; 2-拉黑;'</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>create_time<span class="token punctuation">`</span> <span class="token keyword">timestamp</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>comment_count<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>score<span class="token punctuation">`</span> <span class="token keyword">double</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_user_id<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>user_id<span class="token punctuation">`</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span> <span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span> <span class="token keyword">DEFAULT</span> <span class="token keyword">CHARSET</span><span class="token operator">=</span>utf8<span class="token punctuation">;</span>
<span class="token comment">--</span>
<span class="token comment">-- Table structure for table `login_ticket`</span>
<span class="token comment">--</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> <span class="token punctuation">`</span>login_ticket<span class="token punctuation">`</span><span class="token punctuation">;</span>
 <span class="token keyword">SET</span> character_set_client <span class="token operator">=</span> utf8mb4 <span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span>login_ticket<span class="token punctuation">`</span> <span class="token punctuation">(</span>
  <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>user_id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>ticket<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">45</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">status</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token string">'0'</span> <span class="token keyword">COMMENT</span> <span class="token string">'0-有效; 1-无效;'</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>expired<span class="token punctuation">`</span> <span class="token keyword">timestamp</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_ticket<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>ticket<span class="token punctuation">`</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span> <span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span> <span class="token keyword">DEFAULT</span> <span class="token keyword">CHARSET</span><span class="token operator">=</span>utf8<span class="token punctuation">;</span>
<span class="token comment">--</span>
<span class="token comment">-- Table structure for table `message`</span>
<span class="token comment">--</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> <span class="token punctuation">`</span>message<span class="token punctuation">`</span><span class="token punctuation">;</span>
 <span class="token keyword">SET</span> character_set_client <span class="token operator">=</span> utf8mb4 <span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span>message<span class="token punctuation">`</span> <span class="token punctuation">(</span>
  <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>from_id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>to_id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>conversation_id<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">45</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>content<span class="token punctuation">`</span> <span class="token keyword">text</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">status</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span> <span class="token keyword">COMMENT</span> <span class="token string">'0-未读;1-已读;2-删除;'</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>create_time<span class="token punctuation">`</span> <span class="token keyword">timestamp</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_from_id<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>from_id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_to_id<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>to_id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_conversation_id<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>conversation_id<span class="token punctuation">`</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span> <span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span> <span class="token keyword">DEFAULT</span> <span class="token keyword">CHARSET</span><span class="token operator">=</span>utf8<span class="token punctuation">;</span>
<span class="token comment">--</span>
<span class="token comment">-- Table structure for table `user`</span>
<span class="token comment">--</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span><span class="token punctuation">;</span>
 <span class="token keyword">SET</span> character_set_client <span class="token operator">=</span> utf8mb4 <span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span> <span class="token punctuation">(</span>
  <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>username<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>password<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>salt<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>email<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">type</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span> <span class="token keyword">COMMENT</span> <span class="token string">'0-普通用户; 1-超级管理员; 2-版主;'</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span><span class="token keyword">status</span><span class="token punctuation">`</span> <span class="token keyword">int</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span> <span class="token keyword">COMMENT</span> <span class="token string">'0-未激活; 1-已激活;'</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>activation_code<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>header_url<span class="token punctuation">`</span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token punctuation">`</span>create_time<span class="token punctuation">`</span> <span class="token keyword">timestamp</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
  <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_username<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>username<span class="token punctuation">`</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">KEY</span> <span class="token punctuation">`</span>index_email<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>email<span class="token punctuation">`</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span> <span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token operator">=</span><span class="token number">101</span> <span class="token keyword">DEFAULT</span> <span class="token keyword">CHARSET</span><span class="token operator">=</span>utf8<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>之后会提供一些</p>
<h2 id="2-邮件发送功能"><a href="#2-邮件发送功能" class="headerlink" title="2. 邮件发送功能"></a>2. 邮件发送功能</h2><h3 id="2-1-发送者邮箱中打开SMTP服务"><a href="#2-1-发送者邮箱中打开SMTP服务" class="headerlink" title="2.1 发送者邮箱中打开SMTP服务"></a>2.1 发送者邮箱中打开SMTP服务</h3><p>首先在自己的邮箱(网易、QQ…均可)设置中开启SMTP服务</p>
<p><img src="https://img-blog.csdnimg.cn/2020112412470190.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h3 id="2-2-引入依赖"><a href="#2-2-引入依赖" class="headerlink" title="2.2 引入依赖"></a>2.2 引入依赖</h3><p><strong>pom.xml中引入依赖</strong></p>
<pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token comment">&lt;!--引入邮件发送依赖--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-mail<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="2-3-参数配置"><a href="#2-3-参数配置" class="headerlink" title="2.3 参数配置"></a>2.3 参数配置</h3><p><strong>邮箱参数配置(我使用的是网易邮箱)</strong></p>
<pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># spring 相关配置</span>
<span class="token key atrule">spring</span><span class="token punctuation">:</span>
  <span class="token comment"># 发送者邮箱相关配置</span>
  <span class="token key atrule">mail</span><span class="token punctuation">:</span>
    <span class="token comment"># SMTP服务器域名</span>
    <span class="token key atrule">host</span><span class="token punctuation">:</span> smtp.163.com
    <span class="token comment"># 编码集</span>
    <span class="token key atrule">default-encoding</span><span class="token punctuation">:</span> UTF<span class="token punctuation">-</span><span class="token number">8</span>
    <span class="token comment"># 邮箱用户名</span>
    <span class="token key atrule">username</span><span class="token punctuation">:</span> csp<span class="token important">******@163.com</span>
    <span class="token comment"># 授权码(注意不是邮箱密码！)</span>
    <span class="token key atrule">password</span><span class="token punctuation">:</span> WDS<span class="token important">*******XCQA</span>
    <span class="token comment"># 协议：smtps</span>
    <span class="token key atrule">protocol</span><span class="token punctuation">:</span> smtps
    <span class="token comment"># 详细配置</span>
    <span class="token key atrule">properties</span><span class="token punctuation">:</span>
      <span class="token key atrule">mail</span><span class="token punctuation">:</span>
        <span class="token key atrule">smtp</span><span class="token punctuation">:</span>
          <span class="token comment"># 设置是否需要认证,如果为true,那么用户名和密码就必须的,</span>
          <span class="token comment"># 如果设置false,可以不设置用户名和密码</span>
          <span class="token comment"># (前提要知道对接的平台是否支持无密码进行访问的)</span>
          <span class="token key atrule">auth</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
          <span class="token comment"># STARTTLS[1]  是对纯文本通信协议的扩展。</span>
          <span class="token comment"># 它提供一种方式将纯文本连接升级为加密连接（TLS或SSL）</span>
          <span class="token comment"># 而不是另外使用一个端口作加密通信。</span>
          <span class="token key atrule">starttls</span><span class="token punctuation">:</span>
            <span class="token key atrule">enable</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
            <span class="token key atrule">required</span><span class="token punctuation">:</span> <span class="token boolean important">true</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="2-4-邮件发送工具类"><a href="#2-4-邮件发送工具类" class="headerlink" title="2.4 邮件发送工具类"></a>2.4 邮件发送工具类</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/24/14:29
 * @Description: 邮件发送客户端
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MailClient</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">MailClient</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">JavaMailSender</span> mailSender<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${spring.mail.username}"</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> from<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 发送邮件
     * @param to 收件人
     * @param subject 邮件主题
     * @param content 邮件内容
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sendMail</span><span class="token punctuation">(</span><span class="token class-name">String</span> <span class="token keyword">to</span><span class="token punctuation">,</span><span class="token class-name">String</span> subject<span class="token punctuation">,</span><span class="token class-name">String</span> content<span class="token punctuation">)</span><span class="token punctuation">{</span>

        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">MimeMessage</span> message <span class="token operator">=</span> mailSender<span class="token punctuation">.</span><span class="token function">createMimeMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">MimeMessageHelper</span> helper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MimeMessageHelper</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>

            helper<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span>from<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 发送者</span>
            helper<span class="token punctuation">.</span><span class="token function">setTo</span><span class="token punctuation">(</span><span class="token keyword">to</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 接收者</span>
            helper<span class="token punctuation">.</span><span class="token function">setSubject</span><span class="token punctuation">(</span>subject<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 邮件主题</span>
            helper<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span>content<span class="token punctuation">,</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 邮件内容,第二个参数true表示支持html格式</span>

            mailSender<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>helper<span class="token punctuation">.</span><span class="token function">getMimeMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">MessagingException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"发送邮件失败: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="2-5-测试发送"><a href="#2-5-测试发送" class="headerlink" title="2.5 测试发送"></a>2.5 测试发送</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">MailClient</span> mailClient<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Test</span>
<span class="token keyword">void</span> <span class="token function">test02</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    mailClient<span class="token punctuation">.</span><span class="token function">sendMail</span><span class="token punctuation">(</span><span class="token string">"11xxxxxxx@qq.com"</span><span class="token punctuation">,</span><span class="token string">"TEST"</span><span class="token punctuation">,</span><span class="token string">"测试邮件发送！"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>


<p><img src="https://img-blog.csdnimg.cn/20201124144653126.png#pic_center" alt="在这里插入图片描述"></p>
<p>测试发送邮件成功！</p>
<h3 id="2-6-使用Thymleaf模板引擎发送html格式的邮件"><a href="#2-6-使用Thymleaf模板引擎发送html格式的邮件" class="headerlink" title="2.6 使用Thymleaf模板引擎发送html格式的邮件"></a>2.6 使用Thymleaf模板引擎发送html格式的邮件</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>    
	<span class="token comment">// 激活邮件发送</span>
    <span class="token class-name">Context</span> context <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Context</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// org.thymeleaf.context.Context 包下</span>
    context<span class="token punctuation">.</span><span class="token function">setVariable</span><span class="token punctuation">(</span><span class="token string">"email"</span><span class="token punctuation">,</span> user<span class="token punctuation">.</span><span class="token function">getEmail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// http://csp1999.natapp1.cc/community/activation/用户id/激活码</span>
    <span class="token class-name">String</span> url <span class="token operator">=</span> path <span class="token operator">+</span> contextPath <span class="token operator">+</span> <span class="token string">"/activation/"</span> <span class="token operator">+</span> user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> user<span class="token punctuation">.</span>getActivatio
    context<span class="token punctuation">.</span><span class="token function">setVariable</span><span class="token punctuation">(</span><span class="token string">"url"</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> content <span class="token operator">=</span> templateEngine<span class="token punctuation">.</span><span class="token function">process</span><span class="token punctuation">(</span><span class="token string">"/mail/activation"</span><span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
    mailClient<span class="token punctuation">.</span><span class="token function">sendMail</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getEmail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"激活账号"</span><span class="token punctuation">,</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><img src="https://img-blog.csdnimg.cn/20201124164256902.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h2 id="3-登录与注册功能"><a href="#3-登录与注册功能" class="headerlink" title="3. 登录与注册功能"></a>3. 登录与注册功能</h2><ul>
<li>登录注册功能的验证码目前是存放在<strong>Session</strong>中，之后要存入<strong>Redis</strong>，提高性能，同时也可以解决分布式部署时的<strong>Session</strong>共享问题！</li>
<li>注册功能的邮件发送，比较费时，用户只能干等待邮件发送成功，这种方式不太友好，因此在后端以多线程的方式，分一个线程去处理邮件发送，进而不影响客户端正常给用户的响应问题，不用让用户在页面卡太长时间！</li>
<li>对于登录用户信息判定(比如，账号密码是否错误，用户名是否存在，用户是否激活)等问题，如果每次都查询数据库，效率比较低，为此我们在客户端发送请求——&gt;后端调用数据库，之间加一层 Redis 缓存，来验证用户登录信息是否合法！</li>
</ul>
<h3 id="3-1-登录功能"><a href="#3-1-登录功能" class="headerlink" title="3.1 登录功能"></a>3.1 登录功能</h3><p><img src="https://img-blog.csdnimg.cn/20201124203937440.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h3 id="3-2-注册功能"><a href="#3-2-注册功能" class="headerlink" title="3.2 注册功能"></a>3.2 注册功能</h3><p><img src="https://img-blog.csdnimg.cn/20201124203808469.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h2 id="4-通过cookie获取user登录信息"><a href="#4-通过cookie获取user登录信息" class="headerlink" title="4.通过cookie获取user登录信息"></a>4.通过cookie获取user登录信息</h2><p><strong>客户端通过cookie携带登录凭证向服务器换取user信息</strong>，流程如图：</p>
<p><img src="https://img-blog.csdnimg.cn/20201124210416346.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<p>==这一流程需要借助拦截器<strong>LoginTicketInterceptor 和 LoginRequiredInterceptor</strong>实现==！</p>
<h3 id="LoginTicketInterceptor-java-登录凭证拦截器"><a href="#LoginTicketInterceptor-java-登录凭证拦截器" class="headerlink" title="LoginTicketInterceptor.java 登录凭证拦截器"></a><strong>LoginTicketInterceptor.java</strong> 登录凭证拦截器</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/24/20:54
 * @Description: 登录凭证拦截器
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LoginTicketInterceptor</span> <span class="token keyword">implements</span> <span class="token class-name">HandlerInterceptor</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">UserService</span> userService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">HostHolder</span> hostHolder<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 请求开始前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">preHandle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span>
                             <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">Object</span> handler<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 从cookie中获取凭证</span>
        <span class="token class-name">String</span> ticket <span class="token operator">=</span> <span class="token class-name">CookieUtil</span><span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">"ticket"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>ticket <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 查询凭证</span>
            <span class="token class-name">LoginTicket</span> loginTicket <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findLoginTicket</span><span class="token punctuation">(</span>ticket<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 检查凭证是否有效</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>loginTicket <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> loginTicket<span class="token punctuation">.</span><span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span>
                    <span class="token operator">&amp;&amp;</span> loginTicket<span class="token punctuation">.</span><span class="token function">getExpired</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 根据凭证查询用户</span>
                <span class="token class-name">User</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>loginTicket<span class="token punctuation">.</span><span class="token function">getUserId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 在本次请求中(当前线程)持有该用户信息(要考虑多线程并发的情况,所以借助ThreadLocal)</span>
                hostHolder<span class="token punctuation">.</span><span class="token function">setUser</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 执行请求时
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">postHandle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> 
                           <span class="token class-name">Object</span> handler<span class="token punctuation">,</span> <span class="token class-name">ModelAndView</span> modelAndView<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 从ThreadLocal 中得到当前线程持有的user</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>user <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> modelAndView <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 登录用户的信息存入modelAndView</span>
            modelAndView<span class="token punctuation">.</span><span class="token function">addObject</span><span class="token punctuation">(</span><span class="token string">"loginUser"</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 请求结束后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterCompletion</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span>
                                <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">Object</span> handler<span class="token punctuation">,</span> <span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 从ThreadLocal清除数据</span>
        hostHolder<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="LoginRequiredInterceptor-java-登录请求拦截器"><a href="#LoginRequiredInterceptor-java-登录请求拦截器" class="headerlink" title="LoginRequiredInterceptor.java 登录请求拦截器"></a><strong>LoginRequiredInterceptor.java</strong> 登录请求拦截器</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/24/21:27
 * @Description: 登录请求拦截器
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LoginRequiredInterceptor</span> <span class="token keyword">implements</span> <span class="token class-name">HandlerInterceptor</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">HostHolder</span> hostHolder<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 请求开始前
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">preHandle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> 
                             <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">Object</span> handler<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 判断handler 是否是 HandlerMethod 类型</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>handler <span class="token keyword">instanceof</span> <span class="token class-name">HandlerMethod</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">HandlerMethod</span> handlerMethod <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HandlerMethod</span><span class="token punctuation">)</span> handler<span class="token punctuation">;</span>
            <span class="token comment">// 获取到方法实例</span>
            <span class="token class-name">Method</span> method <span class="token operator">=</span> handlerMethod<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 从方法实例中获得其 LoginRequired 注解</span>
            <span class="token class-name">LoginRequired</span> loginRequired <span class="token operator">=</span> method<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">LoginRequired</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 如果方法实例上标注有 LoginRequired 注解,但 hostHandler中没有 用户信息则拦截</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>loginRequired <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                response<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getContextPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/login"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="将拦截器注册到spring容器中"><a href="#将拦截器注册到spring容器中" class="headerlink" title="将拦截器注册到spring容器中"></a>将拦截器注册到spring容器中</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/24/20:53
 * @Description: 拦截器配置类
 */</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebMvcConfig</span> <span class="token keyword">implements</span> <span class="token class-name">WebMvcConfigurer</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">LoginTicketInterceptor</span> loginTicketInterceptor<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">LoginRequiredInterceptor</span> loginRequiredInterceptor<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addInterceptors</span><span class="token punctuation">(</span><span class="token class-name">InterceptorRegistry</span> registry<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        registry<span class="token punctuation">.</span><span class="token function">addInterceptor</span><span class="token punctuation">(</span>loginTicketInterceptor<span class="token punctuation">)</span>
                <span class="token comment">// 除了静态资源不拦截,其他都拦截</span>
                <span class="token punctuation">.</span><span class="token function">excludePathPatterns</span><span class="token punctuation">(</span><span class="token string">"/**/*.css"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.js"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.png"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.jpg"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.jpeg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        registry<span class="token punctuation">.</span><span class="token function">addInterceptor</span><span class="token punctuation">(</span>loginRequiredInterceptor<span class="token punctuation">)</span>
                <span class="token comment">// 除了静态资源不拦截,其他都拦截</span>
                <span class="token punctuation">.</span><span class="token function">excludePathPatterns</span><span class="token punctuation">(</span><span class="token string">"/**/*.css"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.js"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.png"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.jpg"</span><span class="token punctuation">,</span> <span class="token string">"/**/*.jpeg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="5-文件-头像上传服务器"><a href="#5-文件-头像上传服务器" class="headerlink" title="5. 文件/头像上传服务器"></a>5. 文件/头像上传服务器</h2><h3 id="5-1-效果展示"><a href="#5-1-效果展示" class="headerlink" title="5.1 效果展示"></a>5.1 效果展示</h3><p>上传头像：</p>
<p><img src="https://img-blog.csdnimg.cn/20201125135819535.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<p>头像上传成功：</p>
<p><img src="https://img-blog.csdnimg.cn/20201125135902126.png#pic_center" alt="在这里插入图片描述"></p>
<h3 id="5-2-阿里云OSS文件存储"><a href="#5-2-阿里云OSS文件存储" class="headerlink" title="5.2 阿里云OSS文件存储"></a>5.2 阿里云OSS文件存储</h3><p>入门参考文章：<a target="_blank" rel="noopener" href="https://csp1999.blog.csdn.net/article/details/109412083">springboot操作阿里云OSS实现文件上传，下载，删除(附源码)</a></p>
<p><strong>AliyunOssConfig</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/10/31/13:33
 * @Description: 阿里云 OSS 基本配置
 */</span>
<span class="token comment">// 声明配置类，放入Spring容器</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token comment">// 指定配置文件位置</span>
<span class="token annotation punctuation">@PropertySource</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"classpath:application-aliyun-oss.properties"</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 指定配置文件中自定义属性前缀</span>
<span class="token annotation punctuation">@ConfigurationProperties</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"aliyun"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span><span class="token comment">// lombok</span>
<span class="token annotation punctuation">@Accessors</span><span class="token punctuation">(</span>chain <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token comment">// 开启链式调用</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AliyunOssConfig</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">String</span> endPoint<span class="token punctuation">;</span><span class="token comment">// 地域节点</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> accessKeyId<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> accessKeySecret<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> bucketName<span class="token punctuation">;</span><span class="token comment">// OSS的Bucket名称</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> urlPrefix<span class="token punctuation">;</span><span class="token comment">// Bucket 域名</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> fileHost<span class="token punctuation">;</span><span class="token comment">// 目标文件夹</span>

    <span class="token comment">// 将OSS 客户端交给Spring容器托管</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> OSS <span class="token class-name">OSSClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">OSSClient</span><span class="token punctuation">(</span>endPoint<span class="token punctuation">,</span> accessKeyId<span class="token punctuation">,</span> accessKeySecret<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>FileUploadService</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/10/31/14:30
 * @Description: 文件上传Service (为节省文章中的代码篇幅，不再做接口实现类处理)
 */</span>
<span class="token annotation punctuation">@Service</span><span class="token punctuation">(</span><span class="token string">"fileUploadService"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FileUploadService</span> <span class="token punctuation">{</span>
    <span class="token comment">// 允许上传文件(图片)的格式</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> IMAGE_TYPE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">{</span><span class="token string">".bmp"</span><span class="token punctuation">,</span> <span class="token string">".jpg"</span><span class="token punctuation">,</span>
            <span class="token string">".jpeg"</span><span class="token punctuation">,</span> <span class="token string">".gif"</span><span class="token punctuation">,</span> <span class="token string">".png"</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">FileUploadService</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">OSS</span> ossClient<span class="token punctuation">;</span><span class="token comment">// 注入阿里云oss文件服务器客户端</span>
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">AliyunOssConfig</span> aliyunOssConfig<span class="token punctuation">;</span><span class="token comment">// 注入阿里云OSS基本配置类</span>

    <span class="token comment">/**
     * 文件上传
     * 注：阿里云OSS文件上传官方文档链接：https://help.aliyun.com/document_detail/84781.html?spm=a2c4g.11186623.6.749.11987a7dRYVSzn
     *
     * @param: uploadFile
     * @return: string
     * @create: 2020/10/31 14:36
     * @author: csp1999
     */</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">upload</span><span class="token punctuation">(</span><span class="token class-name">MultipartFile</span> uploadFile<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取oss的Bucket名称</span>
        <span class="token class-name">String</span> bucketName <span class="token operator">=</span> aliyunOssConfig<span class="token punctuation">.</span><span class="token function">getBucketName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取oss的地域节点</span>
        <span class="token class-name">String</span> endpoint <span class="token operator">=</span> aliyunOssConfig<span class="token punctuation">.</span><span class="token function">getEndPoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取oss的AccessKeySecret</span>
        <span class="token class-name">String</span> accessKeySecret <span class="token operator">=</span> aliyunOssConfig<span class="token punctuation">.</span><span class="token function">getAccessKeySecret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取oss的AccessKeyId</span>
        <span class="token class-name">String</span> accessKeyId <span class="token operator">=</span> aliyunOssConfig<span class="token punctuation">.</span><span class="token function">getAccessKeyId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取oss目标文件夹</span>
        <span class="token class-name">String</span> filehost <span class="token operator">=</span> aliyunOssConfig<span class="token punctuation">.</span><span class="token function">getFileHost</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 返回图片上传后返回的url</span>
        <span class="token class-name">String</span> returnImgeUrl <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>

        <span class="token comment">// 校验图片格式</span>
        <span class="token keyword">boolean</span> isLegal <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> type <span class="token operator">:</span> IMAGE_TYPE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">endsWithIgnoreCase</span><span class="token punctuation">(</span>uploadFile<span class="token punctuation">.</span><span class="token function">getOriginalFilename</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> type<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                isLegal <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>isLegal<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 如果图片格式不合法</span>
            logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"图片格式不符合要求..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 获取文件原名称</span>
        <span class="token class-name">String</span> originalFilename <span class="token operator">=</span> uploadFile<span class="token punctuation">.</span><span class="token function">getOriginalFilename</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取文件类型</span>
        <span class="token class-name">String</span> fileType <span class="token operator">=</span> originalFilename<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>originalFilename<span class="token punctuation">.</span><span class="token function">lastIndexOf</span><span class="token punctuation">(</span><span class="token string">"."</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 新文件名称</span>
        <span class="token class-name">String</span> newFileName <span class="token operator">=</span> UUID<span class="token punctuation">.</span><span class="token function">randomUUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> fileType<span class="token punctuation">;</span>
        <span class="token comment">// 构建日期路径, 例如：OSS目标文件夹/2020/10/31/文件名</span>
        <span class="token class-name">String</span> filePath <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleDateFormat</span><span class="token punctuation">(</span><span class="token string">"yyyy/MM/dd"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 文件上传的路径地址</span>
        <span class="token class-name">String</span> uploadImgeUrl <span class="token operator">=</span> filehost <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> filePath <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> newFileName<span class="token punctuation">;</span>

        <span class="token comment">// 获取文件输入流</span>
        <span class="token class-name">InputStream</span> inputStream <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            inputStream <span class="token operator">=</span> uploadFile<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">/**
         * 下面两行代码是重点坑：
         * 现在阿里云OSS 默认图片上传ContentType是image/jpeg
         * 也就是说，获取图片链接后，图片是下载链接，而并非在线浏览链接，
         * 因此，这里在上传的时候要解决ContentType的问题，将其改为image/jpg
         */</span>
        <span class="token class-name">ObjectMetadata</span> meta <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectMetadata</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        meta<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"image/jpg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//文件上传至阿里云OSS</span>
        ossClient<span class="token punctuation">.</span><span class="token function">putObject</span><span class="token punctuation">(</span>bucketName<span class="token punctuation">,</span> uploadImgeUrl<span class="token punctuation">,</span> inputStream<span class="token punctuation">,</span> meta<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">/**
         * 注意：在实际项目中，文件上传成功后，数据库中存储文件地址
         */</span>
        <span class="token comment">// 获取文件上传后的图片返回地址</span>
        returnImgeUrl <span class="token operator">=</span> <span class="token string">"http://"</span> <span class="token operator">+</span> bucketName <span class="token operator">+</span> <span class="token string">"."</span> <span class="token operator">+</span> endpoint <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> uploadImgeUrl<span class="token punctuation">;</span>

        <span class="token keyword">return</span> returnImgeUrl<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="6-敏感词过滤"><a href="#6-敏感词过滤" class="headerlink" title="6. 敏感词过滤"></a>6. 敏感词过滤</h2><p>使用前缀树的数据结构，来进行敏感词过滤：</p>
<ul>
<li>第一步：在resource 目录下新建 sensitive-words.txt 敏感词文本文件</li>
<li>第二步：新建一个敏感词过滤组件 <strong>SensitiveFilter</strong> 类</li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/25/10:56
 * @Description: 敏感词过滤组件
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SensitiveFilter</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">SensitiveFilter</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 替换符</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> REPLACEMENT <span class="token operator">=</span> <span class="token string">"***"</span><span class="token punctuation">;</span>

    <span class="token comment">// 根节点</span>
    <span class="token keyword">private</span> <span class="token class-name">TrieNode</span> rootNode <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TrieNode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@PostConstruct</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">(</span>
                <span class="token class-name">InputStream</span> is <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getResourceAsStream</span><span class="token punctuation">(</span><span class="token string">"sensitive-words.txt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">BufferedReader</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span>is<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">String</span> keyword<span class="token punctuation">;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>keyword <span class="token operator">=</span> reader<span class="token punctuation">.</span><span class="token function">readLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 添加到前缀树</span>
                <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addKeyword</span><span class="token punctuation">(</span>keyword<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"加载敏感词文件失败: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 将一个敏感词添加到前缀树中</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">addKeyword</span><span class="token punctuation">(</span><span class="token class-name">String</span> keyword<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">TrieNode</span> tempNode <span class="token operator">=</span> rootNode<span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> keyword<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">char</span> c <span class="token operator">=</span> keyword<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">TrieNode</span> subNode <span class="token operator">=</span> tempNode<span class="token punctuation">.</span><span class="token function">getSubNode</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>subNode <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 初始化子节点</span>
                subNode <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TrieNode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                tempNode<span class="token punctuation">.</span><span class="token function">addSubNode</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> subNode<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token comment">// 指向子节点,进入下一轮循环</span>
            tempNode <span class="token operator">=</span> subNode<span class="token punctuation">;</span>

            <span class="token comment">// 设置结束标识</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">==</span> keyword<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                tempNode<span class="token punctuation">.</span><span class="token function">setKeywordEnd</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 过滤敏感词
     *
     * @param text 待过滤的文本
     * @return 过滤后的文本
     */</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">filter</span><span class="token punctuation">(</span><span class="token class-name">String</span> text<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">isBlank</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 指针1</span>
        <span class="token class-name">TrieNode</span> tempNode <span class="token operator">=</span> rootNode<span class="token punctuation">;</span>
        <span class="token comment">// 指针2</span>
        <span class="token keyword">int</span> begin <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token comment">// 指针3</span>
        <span class="token keyword">int</span> position <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token comment">// 结果</span>
        <span class="token class-name">StringBuilder</span> sb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">while</span> <span class="token punctuation">(</span>position <span class="token operator">&lt;</span> text<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">char</span> c <span class="token operator">=</span> text<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// 跳过符号</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isSymbol</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 若指针1处于根节点,将此符号计入结果,让指针2向下走一步</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>tempNode <span class="token operator">==</span> rootNode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    begin<span class="token operator">++</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
                <span class="token comment">// 无论符号在开头或中间,指针3都向下走一步</span>
                position<span class="token operator">++</span><span class="token punctuation">;</span>
                <span class="token keyword">continue</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token comment">// 检查下级节点</span>
            tempNode <span class="token operator">=</span> tempNode<span class="token punctuation">.</span><span class="token function">getSubNode</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>tempNode <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 以begin开头的字符串不是敏感词</span>
                sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>text<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span>begin<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 进入下一个位置</span>
                position <span class="token operator">=</span> <span class="token operator">++</span>begin<span class="token punctuation">;</span>
                <span class="token comment">// 重新指向根节点</span>
                tempNode <span class="token operator">=</span> rootNode<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>tempNode<span class="token punctuation">.</span><span class="token function">isKeywordEnd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 发现敏感词,将begin~position字符串替换掉</span>
                sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>REPLACEMENT<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 进入下一个位置</span>
                begin <span class="token operator">=</span> <span class="token operator">++</span>position<span class="token punctuation">;</span>
                <span class="token comment">// 重新指向根节点</span>
                tempNode <span class="token operator">=</span> rootNode<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                <span class="token comment">// 检查下一个字符</span>
                position<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 将最后一批字符计入结果</span>
        sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>text<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>begin<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> sb<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 判断是否为符号</span>
    <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">isSymbol</span><span class="token punctuation">(</span><span class="token class-name">Character</span> c<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 0x2E80~0x9FFF 是东亚文字范围</span>
        <span class="token keyword">return</span> <span class="token operator">!</span><span class="token class-name">CharUtils</span><span class="token punctuation">.</span><span class="token function">isAsciiAlphanumeric</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>c <span class="token operator">&lt;</span> <span class="token number">0x2E80</span> <span class="token operator">||</span> c <span class="token operator">&gt;</span> <span class="token number">0x9FFF</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 前缀树</span>
    <span class="token keyword">private</span> <span class="token keyword">class</span> <span class="token class-name">TrieNode</span> <span class="token punctuation">{</span>

        <span class="token comment">// 关键词结束标识</span>
        <span class="token keyword">private</span> <span class="token keyword">boolean</span> isKeywordEnd <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>

        <span class="token comment">// 子节点(key是下级字符,value是下级节点)</span>
        <span class="token keyword">private</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Character</span><span class="token punctuation">,</span> <span class="token class-name">TrieNode</span><span class="token punctuation">&gt;</span></span> subNodes <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isKeywordEnd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> isKeywordEnd<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setKeywordEnd</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> keywordEnd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            isKeywordEnd <span class="token operator">=</span> keywordEnd<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 添加子节点</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addSubNode</span><span class="token punctuation">(</span><span class="token class-name">Character</span> c<span class="token punctuation">,</span> <span class="token class-name">TrieNode</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            subNodes<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> node<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 获取子节点</span>
        <span class="token keyword">public</span> <span class="token class-name">TrieNode</span> <span class="token function">getSubNode</span><span class="token punctuation">(</span><span class="token class-name">Character</span> c<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> subNodes<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>效果如下图：</p>
<p><img src="https://img-blog.csdnimg.cn/2020112513570330.png#pic_center" alt="在这里插入图片描述"></p>
<h2 id="7-帖子发布与帖子评论"><a href="#7-帖子发布与帖子评论" class="headerlink" title="7.帖子发布与帖子评论"></a>7.帖子发布与帖子评论</h2><h3 id="7-1-帖子发布"><a href="#7-1-帖子发布" class="headerlink" title="7.1 帖子发布"></a>7.1 帖子发布</h3><p><img src="https://img-blog.csdnimg.cn/20201125150945380.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h3 id="7-2-帖子评论"><a href="#7-2-帖子评论" class="headerlink" title="7.2 帖子评论"></a>7.2 帖子评论</h3><p><img src="https://img-blog.csdnimg.cn/20201125151051276.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h2 id="8-私信列表与私信会话聊天"><a href="#8-私信列表与私信会话聊天" class="headerlink" title="8. 私信列表与私信会话聊天"></a>8. 私信列表与私信会话聊天</h2><h3 id="8-1-效果如图"><a href="#8-1-效果如图" class="headerlink" title="8.1 效果如图"></a>8.1 效果如图</h3><h4 id="私信列表"><a href="#私信列表" class="headerlink" title="私信列表"></a>私信列表</h4><p><img src="https://img-blog.csdnimg.cn/2020112618250882.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h4 id="私信详情"><a href="#私信详情" class="headerlink" title="私信详情"></a>私信详情</h4><p><img src="https://img-blog.csdnimg.cn/20201126183009854.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h4 id="私信发送"><a href="#私信发送" class="headerlink" title="私信发送"></a>私信发送</h4><p><img src="https://img-blog.csdnimg.cn/20201126190635383.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h3 id="8-2-DAO层代码"><a href="#8-2-DAO层代码" class="headerlink" title="8.2 DAO层代码"></a>8.2 DAO层代码</h3><h4 id="Mapper接口"><a href="#Mapper接口" class="headerlink" title="Mapper接口"></a>Mapper接口</h4><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/26/16:29
 * @Description:
 */</span>
<span class="token annotation punctuation">@Repository</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">MessageMapper</span> <span class="token punctuation">{</span>

    <span class="token comment">/**
     * 查询当前用户的会话列表,针对每个会话只返回一条最新的私信.
     * @param userId
     * @param offset
     * @param limit
     * @return
     */</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Message</span><span class="token punctuation">&gt;</span></span> <span class="token function">selectConversations</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span> <span class="token keyword">int</span> userId<span class="token punctuation">,</span>
                                      <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"offset"</span><span class="token punctuation">)</span><span class="token keyword">int</span> offset<span class="token punctuation">,</span>
                                      <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"limit"</span><span class="token punctuation">)</span> <span class="token keyword">int</span> limit<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 查询当前用户的会话数量.
     * @param userId
     * @return
     */</span>
    <span class="token keyword">int</span> <span class="token function">selectConversationCount</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 查询某个会话所包含的私信列表.
     * @param conversationId
     * @param offset
     * @param limit
     * @return
     */</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Message</span><span class="token punctuation">&gt;</span></span> <span class="token function">selectLetters</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"conversationId"</span><span class="token punctuation">)</span><span class="token class-name">String</span> conversationId<span class="token punctuation">,</span>
                                <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"offset"</span><span class="token punctuation">)</span><span class="token keyword">int</span> offset<span class="token punctuation">,</span>
                                <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"limit"</span><span class="token punctuation">)</span><span class="token keyword">int</span> limit<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 查询某个会话所包含的私信数量.
     * @param conversationId
     * @return
     */</span>
    <span class="token keyword">int</span> <span class="token function">selectLetterCount</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"conversationId"</span><span class="token punctuation">)</span><span class="token class-name">String</span> conversationId<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 查询未读私信的数量
     * @param userId
     * @param conversationId
     * @return
     */</span>
    <span class="token keyword">int</span> <span class="token function">selectLetterUnreadCount</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span>
                                <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"conversationId"</span><span class="token punctuation">)</span><span class="token class-name">String</span> conversationId<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 新增消息
     * @param message
     * @return
     */</span>
    <span class="token keyword">int</span> <span class="token function">insertMessage</span><span class="token punctuation">(</span><span class="token class-name">Message</span> message<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 修改消息的状态
     * @param ids
     * @param status
     * @return
     */</span>
    <span class="token keyword">int</span> <span class="token function">updateStatus</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"ids"</span><span class="token punctuation">)</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> ids<span class="token punctuation">,</span>
                     <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"status"</span><span class="token punctuation">)</span><span class="token keyword">int</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="SQL实现"><a href="#SQL实现" class="headerlink" title="SQL实现"></a>SQL实现</h4><p>==考验sql能力的时候到了==(∩_∩)！</p>
<pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;</span>
<span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">mapper</span> <span class="token name">PUBLIC</span> <span class="token string">"-//mybatis.org//DTD Mapper 3.0//EN"</span> <span class="token string">"http://mybatis.org/dtd/mybatis-3-mapper.dtd"</span> <span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>mapper</span> <span class="token attr-name">namespace</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.haust.community.mapper.MessageMapper<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>sql</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectFields<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        id, from_id, to_id, conversation_id, content, status, create_time
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>sql</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>sql</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>insertFields<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        from_id, to_id, conversation_id, content, status, create_time
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>sql</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 查询当前用户的会话列表,针对每个会话只返回一条最新的私信. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectConversations<span class="token punctuation">"</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.haust.community.pojo.Message<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        select
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>include</span> <span class="token attr-name">refid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectFields<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>include</span><span class="token punctuation">&gt;</span></span>
        from message
        where id in (
        select max(id) from message
        where status != 2
        and from_id != 1
        and (from_id = #{userId} or to_id = #{userId})
        group by conversation_id
        )
        order by id desc
        limit #{offset}, #{limit}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 查询当前用户的会话数量. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectConversationCount<span class="token punctuation">"</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>java.lang.Integer<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        select count(m.maxid) from (
            select max(id) as maxid from message
            where status != 2
            and from_id != 1
            and (from_id = #{userId} or to_id = #{userId})
            group by conversation_id
        ) as m
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 询某个会话所包含的私信列表. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectLetters<span class="token punctuation">"</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.haust.community.pojo.Message<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        select
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>include</span> <span class="token attr-name">refid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectFields<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>include</span><span class="token punctuation">&gt;</span></span>
        from message
        where status != 2
        and from_id != 1
        and conversation_id = #{conversationId}
        order by id desc
        limit #{offset}, #{limit}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 查询某个会话所包含的私信数量. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectLetterCount<span class="token punctuation">"</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>java.lang.Integer<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        select count(id)
        from message
        where status != 2
        and from_id != 1
        and conversation_id = #{conversationId}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 查询未读私信的数量. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectLetterUnreadCount<span class="token punctuation">"</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>java.lang.Integer<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        select count(id)
        from message
        where status = 0
        and from_id != 1
        and to_id = #{userId}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>conversationId!=null<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            and conversation_id = #{conversationId}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 新增消息. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>insert</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>insertMessage<span class="token punctuation">"</span></span> <span class="token attr-name">parameterType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.haust.community.pojo.Message<span class="token punctuation">"</span></span> <span class="token attr-name">keyProperty</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        insert into message(<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>include</span> <span class="token attr-name">refid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>insertFields<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>include</span><span class="token punctuation">&gt;</span></span>)
        values(#{fromId},#{toId},#{conversationId},#{content},#{status},#{createTime})
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>insert</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- 修改消息的状态. --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>update</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>updateStatus<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        update message set status = #{status}
        where id in
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>foreach</span> <span class="token attr-name">collection</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ids<span class="token punctuation">"</span></span> <span class="token attr-name">item</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">open</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>(<span class="token punctuation">"</span></span> <span class="token attr-name">separator</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>,<span class="token punctuation">"</span></span> <span class="token attr-name">close</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            #{id}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>foreach</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>update</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>mapper</span><span class="token punctuation">&gt;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="Controller-API"><a href="#Controller-API" class="headerlink" title="Controller API"></a>Controller API</h4><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/26/17:42
 * @Description:
 */</span>
<span class="token annotation punctuation">@Controller</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MessageController</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">MessageService</span> messageService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">HostHolder</span> hostHolder<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">UserService</span> userService<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 获取用户私信列表(支持分页) api
     *
     * @param model
     * @param page
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/letter/list"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getLetterList</span><span class="token punctuation">(</span><span class="token class-name">Model</span> model<span class="token punctuation">,</span> <span class="token class-name">Page</span> page<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 分页信息</span>
        page<span class="token punctuation">.</span><span class="token function">setLimit</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setPath</span><span class="token punctuation">(</span><span class="token string">"/letter/list"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setRows</span><span class="token punctuation">(</span>messageService<span class="token punctuation">.</span><span class="token function">findConversationCount</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 会话列表</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Message</span><span class="token punctuation">&gt;</span></span> conversationList <span class="token operator">=</span> messageService<span class="token punctuation">.</span><span class="token function">findConversations</span><span class="token punctuation">(</span>
                user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getLimit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> conversations <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>conversationList <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Message</span> message <span class="token operator">:</span> conversationList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 会话</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"conversation"</span><span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 会话中的消息数量</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"letterCount"</span><span class="token punctuation">,</span> messageService<span class="token punctuation">.</span><span class="token function">findLetterCount</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getConversationId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 会话中的未读消息数量</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"unreadCount"</span><span class="token punctuation">,</span> messageService<span class="token punctuation">.</span><span class="token function">findLetterUnreadCount</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                                            message<span class="token punctuation">.</span><span class="token function">getConversationId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token keyword">int</span> targetId <span class="token operator">=</span> user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> message<span class="token punctuation">.</span><span class="token function">getFromId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> message<span class="token punctuation">.</span><span class="token function">getToId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> message<span class="token punctuation">.</span><span class="token function">getFromId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 目标id(消息接收者id)</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"target"</span><span class="token punctuation">,</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>targetId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 该会话加入会话列表</span>
                conversations<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 会话列表加入model中</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"conversations"</span><span class="token punctuation">,</span> conversations<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 查询未读消息数量</span>
        <span class="token keyword">int</span> letterUnreadCount <span class="token operator">=</span> messageService<span class="token punctuation">.</span><span class="token function">findLetterUnreadCount</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 未读消息数量加入model中</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"letterUnreadCount"</span><span class="token punctuation">,</span> letterUnreadCount<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token string">"/site/letter"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 私信详情 api
     * @param conversationId
     * @param page
     * @param model
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/letter/detail/{conversationId}"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getLetterDetail</span><span class="token punctuation">(</span>
            <span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">"conversationId"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> conversationId<span class="token punctuation">,</span> <span class="token class-name">Page</span> page<span class="token punctuation">,</span> <span class="token class-name">Model</span> model<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 分页信息</span>
        page<span class="token punctuation">.</span><span class="token function">setLimit</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setPath</span><span class="token punctuation">(</span><span class="token string">"/letter/detail/"</span> <span class="token operator">+</span> conversationId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setRows</span><span class="token punctuation">(</span>messageService<span class="token punctuation">.</span><span class="token function">findLetterCount</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 私信列表</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Message</span><span class="token punctuation">&gt;</span></span> letterList <span class="token operator">=</span> messageService<span class="token punctuation">.</span><span class="token function">findLetters</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">,</span> 
                                                              page<span class="token punctuation">.</span><span class="token function">getOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getLimit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> letters <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>letterList <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Message</span> message <span class="token operator">:</span> letterList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 会话消息</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"letter"</span><span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 消息发送者信息</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"fromUser"</span><span class="token punctuation">,</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getFromId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                letters<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 会话消息列表存入model</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"letters"</span><span class="token punctuation">,</span> letters<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 私信目标存入model</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"target"</span><span class="token punctuation">,</span> <span class="token function">getLetterTarget</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 设置已读</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> ids <span class="token operator">=</span> <span class="token function">getLetterIds</span><span class="token punctuation">(</span>letterList<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>ids<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            messageService<span class="token punctuation">.</span><span class="token function">readMessage</span><span class="token punctuation">(</span>ids<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> <span class="token string">"/site/letter-detail"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 获取私信目标信息</span>
    <span class="token keyword">private</span> <span class="token class-name">User</span> <span class="token function">getLetterTarget</span><span class="token punctuation">(</span><span class="token class-name">String</span> conversationId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 分割conversationId  eg: 111_112  ---&gt; [111,222]</span>
        <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ids <span class="token operator">=</span> conversationId<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"_"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> id0 <span class="token operator">=</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">parseInt</span><span class="token punctuation">(</span>ids<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> id1 <span class="token operator">=</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">parseInt</span><span class="token punctuation">(</span>ids<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> id0<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>id1<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>id0<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 根据会话消息id集合批量签收(读取)多条消息</span>
    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> <span class="token function">getLetterIds</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Message</span><span class="token punctuation">&gt;</span></span> letterList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> ids <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>letterList <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Message</span> message <span class="token operator">:</span> letterList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> message<span class="token punctuation">.</span><span class="token function">getToId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> message<span class="token punctuation">.</span><span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    ids<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> ids<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 私信发送操作
     * @param toName
     * @param content
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/letter/send"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@ResponseBody</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">sendLetter</span><span class="token punctuation">(</span><span class="token class-name">String</span> toName<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">User</span> target <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findUserByName</span><span class="token punctuation">(</span>toName<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>target <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"目标用户不存在!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 开始构建会话消息对象</span>
        <span class="token class-name">Message</span> message <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        message<span class="token punctuation">.</span><span class="token function">setFromId</span><span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        message<span class="token punctuation">.</span><span class="token function">setToId</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getFromId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> message<span class="token punctuation">.</span><span class="token function">getToId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            message<span class="token punctuation">.</span><span class="token function">setConversationId</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getFromId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"_"</span> <span class="token operator">+</span> message<span class="token punctuation">.</span><span class="token function">getToId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            message<span class="token punctuation">.</span><span class="token function">setConversationId</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getToId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"_"</span> <span class="token operator">+</span> message<span class="token punctuation">.</span><span class="token function">getFromId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        message<span class="token punctuation">.</span><span class="token function">setContent</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
        message<span class="token punctuation">.</span><span class="token function">setCreateTime</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        messageService<span class="token punctuation">.</span><span class="token function">addMessage</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="9-全局异常捕获与处理"><a href="#9-全局异常捕获与处理" class="headerlink" title="9. 全局异常捕获与处理"></a>9. 全局异常捕获与处理</h2><h3 id="404页面展示"><a href="#404页面展示" class="headerlink" title="404页面展示"></a>404页面展示</h3><p><img src="https://img-blog.csdnimg.cn/20201126202500103.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center"></p>
<h3 id="错误页面展示"><a href="#错误页面展示" class="headerlink" title="错误页面展示"></a>错误页面展示</h3><p><img src="https://img-blog.csdnimg.cn/20201126202542437.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p>
<h3 id="统一异常处理"><a href="#统一异常处理" class="headerlink" title="统一异常处理"></a>统一异常处理</h3><blockquote>
<p>相关注解介绍</p>
</blockquote>
<ul>
<li><code>@ControllerAdvice</code><ul>
<li>用于==修饰类==，表示该类是<strong>Controller</strong> 的全局适配类。</li>
<li>在此类中，可以对<strong>Controller</strong> 进行如下三种全局配置：<ul>
<li><span class="github-emoji"><span>🚡</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f6a1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>  异常处理方案</li>
<li><span class="github-emoji"><span>👶</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f476.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span> 绑定数据方案</li>
<li><span class="github-emoji"><span>🐤</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f424.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span> 绑定参数方案</li>
</ul>
</li>
</ul>
</li>
<li><code>@ExceptionHandler</code>(我们实例中使用则个注解修饰方法)<ul>
<li>用于==修饰方法==，该方法会在<strong>Controller</strong> 出现异常后被调用，用于<u>处理捕获到的异常</u>。</li>
</ul>
</li>
<li><code>@ModelAttribute</code><ul>
<li>用于==修饰方法==，该方法回在<strong>Controller</strong> 方法执行前被调用，用于<u>为<strong>Model</strong> 对象绑定参数</u>。</li>
</ul>
</li>
<li><code>@DataBinder</code><ul>
<li>用于==修饰方法==，该方法回在<strong>Controller</strong> 方法执行前被调用，用于<u>绑定参数的转换器</u>。</li>
</ul>
</li>
</ul>
<blockquote>
<p>实例代码</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/26/20:39
 * @Description: 异常通知类
 */</span>
<span class="token comment">// 所有带 @Controller 注解的类都会被扫描到</span>
<span class="token annotation punctuation">@ControllerAdvice</span><span class="token punctuation">(</span>annotations <span class="token operator">=</span> <span class="token class-name">Controller</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ExceptionAdvice</span> <span class="token punctuation">{</span>

    <span class="token comment">// 声明日志工厂</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">ExceptionAdvice</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 自定义异常处理器,覆盖spring boot原来的异常处理器
     * @param e 异常对象
     * @param request 请求
     * @param response 响应
     * @throws IOException
     */</span>
    <span class="token annotation punctuation">@ExceptionHandler</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token class-name">Exception</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token comment">// 标识该方法是用来做异常处理的，处理的异常级别为Exception</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">handleException</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">,</span> <span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> 
                                <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 记录异常信息</span>
        logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"请求 URL : {} , 异常信息 : {}"</span><span class="token punctuation">,</span>request<span class="token punctuation">.</span><span class="token function">getRequestURL</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 逐条记录错误日志</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">StackTraceElement</span> element <span class="token operator">:</span> e<span class="token punctuation">.</span><span class="token function">getStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>element<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token class-name">String</span> xRequestedWith <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getHeader</span><span class="token punctuation">(</span><span class="token string">"x-requested-with"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"XMLHttpRequest"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>xRequestedWith<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"application/plain;charset=utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">PrintWriter</span> writer <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            writer<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"服务器异常!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            response<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getContextPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="切面统一记录日志"><a href="#切面统一记录日志" class="headerlink" title="切面统一记录日志"></a>切面统一记录日志</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/26/21:12
 * @Description: 自定义日志处理组件
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token annotation punctuation">@Aspect</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ServiceLogAspect</span> <span class="token punctuation">{</span>

    <span class="token comment">// 获取日志工厂</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">ServiceLogAspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 切入点
     */</span>
    <span class="token annotation punctuation">@Pointcut</span><span class="token punctuation">(</span><span class="token string">"execution(* com.haust.community.service.*.*(..))"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">pointcut</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 前置通知,在切面之前执行
     *
     * @param joinPoint
     */</span>
    <span class="token annotation punctuation">@Before</span><span class="token punctuation">(</span><span class="token string">"pointcut()"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token class-name">JoinPoint</span> joinPoint<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 用户[1.2.3.4],在[xxx],访问了[com.nowcoder.community.service.xxx()].</span>
        <span class="token class-name">ServletRequestAttributes</span> attributes <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ServletRequestAttributes</span><span class="token punctuation">)</span> <span class="token class-name">RequestContextHolder</span><span class="token punctuation">.</span><span class="token function">getRequestAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">HttpServletRequest</span> request <span class="token operator">=</span> attributes<span class="token punctuation">.</span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> ip <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getRemoteHost</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> now <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleDateFormat</span><span class="token punctuation">(</span><span class="token string">"yyyy-MM-dd HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> target <span class="token operator">=</span> joinPoint<span class="token punctuation">.</span><span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getDeclaringTypeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"."</span> <span class="token operator">+</span> joinPoint<span class="token punctuation">.</span><span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"用户[%s],在[%s],访问了[%s]."</span><span class="token punctuation">,</span> ip<span class="token punctuation">,</span> now<span class="token punctuation">,</span> target<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 后置通知,在切面之后执行
     */</span>
    <span class="token annotation punctuation">@After</span><span class="token punctuation">(</span><span class="token string">"pointcut()"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doAfter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"----------doAfter----------"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 切入点拦截的方法执行结束后，捕获返回内容
     *
     * @param result
     */</span>
    <span class="token annotation punctuation">@AfterReturning</span><span class="token punctuation">(</span>returning <span class="token operator">=</span> <span class="token string">"result"</span><span class="token punctuation">,</span> pointcut <span class="token operator">=</span> <span class="token string">"pointcut()"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doAfterRuturn</span><span class="token punctuation">(</span><span class="token class-name">Object</span> result<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"捕获返回内容 : {}"</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="10-Redis-实现点赞-关注-粉丝列表"><a href="#10-Redis-实现点赞-关注-粉丝列表" class="headerlink" title="10. Redis 实现点赞/关注/粉丝列表"></a>10. Redis 实现点赞/关注/粉丝列表</h2><h4 id="生成Redis-Key的工具类"><a href="#生成Redis-Key的工具类" class="headerlink" title="生成Redis Key的工具类:"></a>生成Redis Key的工具类:</h4><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/27/20:34
 * @Description: Redis Key的工具类
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RedisKeyUtil</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> SPLIT <span class="token operator">=</span> <span class="token string">":"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_ENTITY_LIKE <span class="token operator">=</span> <span class="token string">"like:entity"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_USER_LIKE <span class="token operator">=</span> <span class="token string">"like:user"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_FOLLOWEE <span class="token operator">=</span> <span class="token string">"followee"</span><span class="token punctuation">;</span><span class="token comment">// 关注某人</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_FOLLOWER <span class="token operator">=</span> <span class="token string">"follower"</span><span class="token punctuation">;</span><span class="token comment">// 某人关注我</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_KAPTCHA <span class="token operator">=</span> <span class="token string">"kaptcha"</span><span class="token punctuation">;</span><span class="token comment">// 验证码key的前缀</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_TICKET <span class="token operator">=</span> <span class="token string">"ticket"</span><span class="token punctuation">;</span><span class="token comment">// 登录凭证key的前缀</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_USER <span class="token operator">=</span> <span class="token string">"user"</span><span class="token punctuation">;</span><span class="token comment">// 登录用户key的前缀</span>

    <span class="token comment">/**
     * 某个实体赞的key
     * &lt;p&gt;
     * key ---&gt; like:entity:entityType:entityId -&gt; set(userId)
     *
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getEntityLikeKey</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_ENTITY_LIKE <span class="token operator">+</span> SPLIT <span class="token operator">+</span> entityType <span class="token operator">+</span> SPLIT <span class="token operator">+</span> entityId<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 某个用户累计的赞的key
     * &lt;p&gt;
     * key ---&gt; like:user:userId -&gt; int
     *
     * @param userId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getUserLikeKey</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_USER_LIKE <span class="token operator">+</span> SPLIT <span class="token operator">+</span> userId<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 某个用户关注某个实体的集合key
     * &lt;p&gt;
     * key
     * ---&gt; followee:userId:entityType
     * ---&gt; zset(entityId,now),zset为有序集合,以now作为排序分数
     * now表示当前时间的时间数,可以根据时间大小排序
     *
     *
     * @param userId
     * @param entityType
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getFolloweeKey</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_FOLLOWEE <span class="token operator">+</span> SPLIT <span class="token operator">+</span> userId <span class="token operator">+</span> SPLIT <span class="token operator">+</span> entityType<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 某个实体拥有的粉丝集合key
     * &lt;p&gt;
     * key ---&gt; follower:entityType:entityId -&gt; zset(userId,now)
     *
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getFollowerKey</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_FOLLOWER <span class="token operator">+</span> SPLIT <span class="token operator">+</span> entityType <span class="token operator">+</span> SPLIT <span class="token operator">+</span> entityId<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 登录验证码的key
     *
     * @param owner 验证码所属者
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getKaptchaKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> owner<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_KAPTCHA <span class="token operator">+</span> SPLIT <span class="token operator">+</span> owner<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 登录的凭证的key
     *
     * @param ticket
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getTicketKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> ticket<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_TICKET <span class="token operator">+</span> SPLIT <span class="token operator">+</span> ticket<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 用户的key
     *
     * @param userId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getUserKey</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> PREFIX_USER <span class="token operator">+</span> SPLIT <span class="token operator">+</span> userId<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="Service层："><a href="#Service层：" class="headerlink" title="Service层："></a>Service层：</h4><p><strong>LikeService</strong>.java</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/27/20:39
 * @Description: 点赞Service 存入Redis 缓存
 */</span>
<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LikeService</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 点赞操作
     *
     * @param userId       点赞用户的id
     * @param entityType   点赞实体的类型
     * @param entityId     点赞实体的id
     * @param entityUserId 被点赞实体的用户id
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">like</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityUserId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SessionCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">RedisOperations</span> operations<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">DataAccessException</span> <span class="token punctuation">{</span>
                <span class="token comment">// 某帖子实体点赞集合的key</span>
                <span class="token class-name">String</span> entityLikeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getEntityLikeKey</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 某个用户累计的赞的key</span>
                <span class="token class-name">String</span> userLikeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getUserLikeKey</span><span class="token punctuation">(</span>entityUserId<span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 查询entityLikeKey对应的集合中是否已经存在当前userId</span>
                <span class="token keyword">boolean</span> isMember <span class="token operator">=</span> operations<span class="token punctuation">.</span><span class="token function">opsForSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isMember</span><span class="token punctuation">(</span>entityLikeKey<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 开启redis事务</span>
                operations<span class="token punctuation">.</span><span class="token function">multi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// userId 已经存在，即当前用户已经为该帖子点过赞</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>isMember<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 取消这个赞</span>
                    operations<span class="token punctuation">.</span><span class="token function">opsForSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>entityLikeKey<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token comment">// 被点赞用户获赞数减少1</span>
                    operations<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">decrement</span><span class="token punctuation">(</span>userLikeKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                    <span class="token comment">// userId 不存在，即当前用户还没为该帖子点过赞，直接点赞即可</span>
                    operations<span class="token punctuation">.</span><span class="token function">opsForSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>entityLikeKey<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token comment">// 被点赞用户获赞数增加1</span>
                    operations<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">increment</span><span class="token punctuation">(</span>userLikeKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>

                <span class="token comment">// 执行redis事务</span>
                <span class="token keyword">return</span> operations<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询某帖子实体点赞的数量
     *
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">long</span> <span class="token function">findEntityLikeCount</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        <span class="token comment">// 某帖子实体点赞集合的key</span>
        <span class="token class-name">String</span> entityLikeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getEntityLikeKey</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 统计该帖子实体的点赞集合中的数据数量，即点赞数</span>
        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span>entityLikeKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询某人对某帖子实体的点赞状态
     * 0未点赞/1已点赞
     *
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">findEntityLikeStatus</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 某帖子实体点赞集合的key</span>
        <span class="token class-name">String</span> entityLikeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getEntityLikeKey</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isMember</span><span class="token punctuation">(</span>entityLikeKey<span class="token punctuation">,</span> userId<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询某个用户累计获得的赞
     *
     * @param userId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">findUserLikeCount</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">String</span> userLikeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getUserLikeKey</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Integer</span> count <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">)</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>userLikeKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> count <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> count<span class="token punctuation">.</span><span class="token function">intValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>FollowService</strong>.java</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/28/9:41
 * @Description: 关注Service 存入Redis 缓存
 */</span>
<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FollowService</span> <span class="token keyword">implements</span> <span class="token class-name">CommunityConstant</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">UserService</span> userService<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 用户关注了某个实体
     *
     * @param userId
     * @param entityType
     * @param entityId
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">follow</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SessionCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">RedisOperations</span> operations<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">DataAccessException</span> <span class="token punctuation">{</span>
                <span class="token comment">// 某个用户所关注的实体的集合key</span>
                <span class="token class-name">String</span> followeeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFolloweeKey</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> entityType<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 某个实体拥有的粉丝集合key</span>
                <span class="token class-name">String</span> followerKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFollowerKey</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 开启redis事务</span>
                operations<span class="token punctuation">.</span><span class="token function">multi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 用户所关注的实体的集合新增一条关注数据</span>
                operations<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>followeeKey<span class="token punctuation">,</span> entityId<span class="token punctuation">,</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 实体拥有的粉丝集合新增一个粉丝</span>
                operations<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>followerKey<span class="token punctuation">,</span> userId<span class="token punctuation">,</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 执行redis事务</span>
                <span class="token keyword">return</span> operations<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 用户取消关注了某个实体
     *
     * @param userId
     * @param entityType
     * @param entityId
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">unfollow</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SessionCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">RedisOperations</span> operations<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">DataAccessException</span> <span class="token punctuation">{</span>
                <span class="token comment">// 某个用户所关注的实体的集合key</span>
                <span class="token class-name">String</span> followeeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFolloweeKey</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> entityType<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 某个实体拥有的粉丝集合key</span>
                <span class="token class-name">String</span> followerKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFollowerKey</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 开启redis事务</span>
                operations<span class="token punctuation">.</span><span class="token function">multi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 用户关注所关注的实体的集合减少一条关注数据</span>
                operations<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>followeeKey<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 实体拥有的粉丝集合减少一个粉丝</span>
                operations<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>followerKey<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 执行redis事务</span>
                <span class="token keyword">return</span> operations<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询关注的实体的数量
     *
     * @param userId
     * @param entityType
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">long</span> <span class="token function">findFolloweeCount</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 某个用户所关注的实体的集合key</span>
        <span class="token class-name">String</span> followeeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFolloweeKey</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> entityType<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">zCard</span><span class="token punctuation">(</span>followeeKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询实体的粉丝的数量
     *
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">long</span> <span class="token function">findFollowerCount</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 某个实体拥有的粉丝集合key</span>
        <span class="token class-name">String</span> followerKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFollowerKey</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">zCard</span><span class="token punctuation">(</span>followerKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询当前用户是否已关注该实体
     *
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">hasFollowed</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 某个用户所关注的实体的集合key</span>
        <span class="token class-name">String</span> followeeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFolloweeKey</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> entityType<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">score</span><span class="token punctuation">(</span>followeeKey<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询某用户关注的人
     *
     * @param userId
     * @param offset
     * @param limit
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">findFollowees</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> offset<span class="token punctuation">,</span> <span class="token keyword">int</span> limit<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 某个用户所关注的用户集合key</span>
        <span class="token class-name">String</span> followeeKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFolloweeKey</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> ENTITY_TYPE_USER<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 分页</span>
        <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> targetIds <span class="token operator">=</span> 
            redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reverseRange</span><span class="token punctuation">(</span>followeeKey<span class="token punctuation">,</span> offset<span class="token punctuation">,</span> offset <span class="token operator">+</span> limit <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 判空</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>targetIds <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 结果拼接封装成list</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Integer</span> targetId <span class="token operator">:</span> targetIds<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">User</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>targetId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 存入用户信息</span>
            map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">Double</span> score <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">score</span><span class="token punctuation">(</span>followeeKey<span class="token punctuation">,</span> targetId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>score<span class="token operator">+</span><span class="token string">"====================================================="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 存入时间(score中 存入的是日期毫秒数,Double类型)</span>
            map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"followTime"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>score<span class="token punctuation">.</span><span class="token function">longValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> list<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询某用户的粉丝
     *
     * @param userId
     * @param offset
     * @param limit
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">findFollowers</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> offset<span class="token punctuation">,</span> <span class="token keyword">int</span> limit<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        <span class="token comment">// 某个实体拥有的粉丝集合key</span>
        <span class="token class-name">String</span> followerKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getFollowerKey</span><span class="token punctuation">(</span>ENTITY_TYPE_USER<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 分页</span>
        <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> targetIds <span class="token operator">=</span> 
            redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reverseRange</span><span class="token punctuation">(</span>followerKey<span class="token punctuation">,</span> offset<span class="token punctuation">,</span> offset <span class="token operator">+</span> limit <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 判空</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>targetIds <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 结果拼接封装成list</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Integer</span> targetId <span class="token operator">:</span> targetIds<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">User</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>targetId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">Double</span> score <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">score</span><span class="token punctuation">(</span>followerKey<span class="token punctuation">,</span> targetId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"followTime"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>score<span class="token punctuation">.</span><span class="token function">longValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> list<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="controller层："><a href="#controller层：" class="headerlink" title="controller层："></a>controller层：</h4><p><strong>LikeController</strong>.java</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/27/20:59
 * @Description: 点赞controller
 */</span>
<span class="token annotation punctuation">@Controller</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LikeController</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">LikeService</span> likeService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">HostHolder</span> hostHolder<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 用户点赞操作
     * @param entityType 帖子实体类型
     * @param entityId 帖子实体id
     * @param entityUserId 被点赞实体的用户id
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/like"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@ResponseBody</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">like</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">,</span> <span class="token keyword">int</span> entityUserId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取登录用户</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 进行点赞</span>
        likeService<span class="token punctuation">.</span><span class="token function">like</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">,</span> entityUserId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 点赞的数量</span>
        <span class="token keyword">long</span> likeCount <span class="token operator">=</span> likeService<span class="token punctuation">.</span><span class="token function">findEntityLikeCount</span><span class="token punctuation">(</span>entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 点赞的状态</span>
        <span class="token keyword">int</span> likeStatus <span class="token operator">=</span> likeService<span class="token punctuation">.</span><span class="token function">findEntityLikeStatus</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 返回的结果</span>
        <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"likeCount"</span><span class="token punctuation">,</span> likeCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
        map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"likeStatus"</span><span class="token punctuation">,</span> likeStatus<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> map<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>FllowController</strong>.java</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/11/28/9:48
 * @Description: 关注Controller
 */</span>
<span class="token annotation punctuation">@Controller</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FollowController</span> <span class="token keyword">implements</span> <span class="token class-name">CommunityConstant</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">FollowService</span> followService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">HostHolder</span> hostHolder<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">UserService</span> userService<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 关注操作
     *
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/follow"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@ResponseBody</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">follow</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取当前用户</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 关注</span>
        followService<span class="token punctuation">.</span><span class="token function">follow</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"已关注!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 取消关注操作
     *
     * @param entityType
     * @param entityId
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/unfollow"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@ResponseBody</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">unfollow</span><span class="token punctuation">(</span><span class="token keyword">int</span> entityType<span class="token punctuation">,</span> <span class="token keyword">int</span> entityId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取当前用户</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 取消关注</span>
        followService<span class="token punctuation">.</span><span class="token function">unfollow</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> entityType<span class="token punctuation">,</span> entityId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"已取消关注!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询"我"关注的人
     *
     * @param userId
     * @param page
     * @param model
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/followees/{userId}"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getFollowees</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span> <span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token class-name">Page</span> page<span class="token punctuation">,</span> <span class="token class-name">Model</span> model<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 查询用户信息</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>user <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"该用户不存在!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// user 存入 model</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>

        page<span class="token punctuation">.</span><span class="token function">setLimit</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setPath</span><span class="token punctuation">(</span><span class="token string">"/followees/"</span> <span class="token operator">+</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setRows</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> followService<span class="token punctuation">.</span><span class="token function">findFolloweeCount</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> ENTITY_TYPE_USER<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 查询用户关注的人的 list 列表</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> userList <span class="token operator">=</span> 
            followService<span class="token punctuation">.</span><span class="token function">findFollowees</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getLimit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 循环list 并拼接每条用户信息</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>userList <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">:</span> userList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">User</span> u <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">User</span><span class="token punctuation">)</span> map<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 判断当前用户是否已经关注了某个用户</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"hasFollowed"</span><span class="token punctuation">,</span> <span class="token function">hasFollowed</span><span class="token punctuation">(</span>u<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// userList 存入 model</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"users"</span><span class="token punctuation">,</span> userList<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token string">"/site/followee"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 查询关注"我"的人(粉丝)
     *
     * @param userId
     * @param page
     * @param model
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/followers/{userId}"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getFollowers</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span> <span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token class-name">Page</span> page<span class="token punctuation">,</span> <span class="token class-name">Model</span> model<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 查询用户信息</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">findUserById</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>user <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"该用户不存在!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// user 存入 model</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>

        page<span class="token punctuation">.</span><span class="token function">setLimit</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setPath</span><span class="token punctuation">(</span><span class="token string">"/followers/"</span> <span class="token operator">+</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        page<span class="token punctuation">.</span><span class="token function">setRows</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> followService<span class="token punctuation">.</span><span class="token function">findFollowerCount</span><span class="token punctuation">(</span>ENTITY_TYPE_USER<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 查询用户粉丝的 list 列表</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Map</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> userList <span class="token operator">=</span> 
            followService<span class="token punctuation">.</span><span class="token function">findFollowers</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">.</span><span class="token function">getLimit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 循环list 并拼接每条用户信息</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>userList <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">:</span> userList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">User</span> u <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">User</span><span class="token punctuation">)</span> map<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 判断当前用户是否已经关注了某个用户</span>
                map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"hasFollowed"</span><span class="token punctuation">,</span> <span class="token function">hasFollowed</span><span class="token punctuation">(</span>u<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// userList 存入 model</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"users"</span><span class="token punctuation">,</span> userList<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token string">"/site/follower"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 判断当前用户是否已经关注了某个用户</span>
    <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">hasFollowed</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 判断当前用户是否登录</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 判断当前用户是否已经关注了某个用户</span>
        <span class="token keyword">return</span> followService<span class="token punctuation">.</span><span class="token function">hasFollowed</span><span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> ENTITY_TYPE_USER<span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="11-Kafka-构建异步消息系统-消息发送和通知"><a href="#11-Kafka-构建异步消息系统-消息发送和通知" class="headerlink" title="11. Kafka 构建异步消息系统(消息发送和通知)"></a>11. Kafka 构建异步消息系统(消息发送和通知)</h2><p><strong>Kafka</strong> 的下载与安装，参考 <a target="_blank" rel="noopener" href="https://csp1999.blog.csdn.net/article/details/110310012">Linux环境下Kafka的安装与使用</a></p>
<p><img src="https://img-blog.csdnimg.cn/20201129133653827.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<p>效果如图：</p>
<p><img src="https://img-blog.csdnimg.cn/2020113013371967.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h2 id="12-ElasticSearch-实现社区全局搜索功能"><a href="#12-ElasticSearch-实现社区全局搜索功能" class="headerlink" title="12. ElasticSearch 实现社区全局搜索功能"></a>12. ElasticSearch 实现社区全局搜索功能</h2><h3 id="12-1-ES-介绍"><a href="#12-1-ES-介绍" class="headerlink" title="12.1 ES 介绍"></a>12.1 ES 介绍</h3><p><img src="https://img-blog.csdnimg.cn/20201130134121566.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<ul>
<li><p>官网地址：<a target="_blank" rel="noopener" href="https://www.elastic.co/cn/">https://www.elastic.co/cn/</a></p>
</li>
<li><p>官方文档地址：<a target="_blank" rel="noopener" href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html</a></p>
</li>
<li><p>下载地址：<a target="_blank" rel="noopener" href="https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-6-1">https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-6-1</a></p>
</li>
</ul>
<p>ES 入门参考文章：<a target="_blank" rel="noopener" href="https://csp1999.blog.csdn.net/article/details/110392198">Linux环境下ElasticSearch的安装与使用(SpringBoot整合云服务器上的ElasticSearch)</a></p>
<h3 id="12-2-论坛搜索的功能实现"><a href="#12-2-论坛搜索的功能实现" class="headerlink" title="12.2 论坛搜索的功能实现"></a>12.2 论坛搜索的功能实现</h3><p><img src="https://img-blog.csdnimg.cn/20201201093015216.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="12-3-效果展示"><a href="#12-3-效果展示" class="headerlink" title="12.3 效果展示"></a>12.3 效果展示</h3><p><img src="https://img-blog.csdnimg.cn/20201201132012370.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h2 id="13-Spring-Security-权限控制"><a href="#13-Spring-Security-权限控制" class="headerlink" title="13. Spring Security 权限控制"></a>13. Spring Security 权限控制</h2><h3 id="13-1-简介"><a href="#13-1-简介" class="headerlink" title="13.1 简介"></a>13.1 简介</h3><p><a target="_blank" rel="noopener" href="https://spring.io/projects/spring-security">Spring Security官方文档</a></p>
<p><img src="https://img-blog.csdnimg.cn/20201201135223617.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<ul>
<li>入门参考文章：<a target="_blank" rel="noopener" href="https://blog.csdn.net/fangchao2011/article/details/106501059">SpringBoot2.3整合SpringSecurity</a></li>
<li>进阶参考文章：[<a target="_blank" rel="noopener" href="http://www.spring4all.com/article/428][http://www.spring4all.com/article/428]">http://www.spring4all.com/article/428][http://www.spring4all.com/article/428]</a></li>
<li>案例Demo参考文章：<a target="_blank" rel="noopener" href="https://csp1999.blog.csdn.net/article/details/110497775">SpringBoot整合SpringSecurity做认证和权限控制案例(含Demo代码)</a></li>
</ul>
<h3 id="13-2-项目中的权限控制介绍"><a href="#13-2-项目中的权限控制介绍" class="headerlink" title="13.2 项目中的权限控制介绍"></a>13.2 项目中的权限控制介绍</h3><p><img src="https://img-blog.csdnimg.cn/20201201171437750.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="13-3-使用Spring-Security-替代原来的登录拦截器"><a href="#13-3-使用Spring-Security-替代原来的登录拦截器" class="headerlink" title="13.3 使用Spring Security 替代原来的登录拦截器"></a>13.3 使用Spring Security 替代原来的登录拦截器</h3><h4 id="13-3-1-pom-xml-中新增相关依赖"><a href="#13-3-1-pom-xml-中新增相关依赖" class="headerlink" title="13.3.1 pom.xml 中新增相关依赖"></a>13.3.1 pom.xml 中新增相关依赖</h4><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security --&gt;</span>
<span class="token comment">&lt;!--spring security--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-security<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="13-3-2-SecurityConfig-配置类"><a href="#13-3-2-SecurityConfig-配置类" class="headerlink" title="13.3.2 SecurityConfig 配置类"></a>13.3.2 SecurityConfig 配置类</h4><p>首先先从<strong>WebMvcConfig.java</strong> 中 注释掉原来自定义的登录拦截器注册：<strong>LoginRequiredInterceptor</strong></p>
<p>然后再进行<strong>Spring Security</strong> 相关配置：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/03/9:57
 * @Description: Spring Security 配置类
 */</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SecurityConfig</span> <span class="token keyword">extends</span> <span class="token class-name">WebSecurityConfigurerAdapter</span> <span class="token keyword">implements</span> <span class="token class-name">CommunityConstant</span> <span class="token punctuation">{</span>

    <span class="token comment">/**
     * 对要拦截的目标资源进行配置
     *
     * @param web
     * @throws Exception
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">configure</span><span class="token punctuation">(</span><span class="token class-name">WebSecurity</span> web<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 忽略拦截 resources 下的所有静态资源</span>
        web<span class="token punctuation">.</span><span class="token function">ignoring</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span><span class="token string">"/resources/**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 用于对授权进行处理(核心)
     *
     * @param http
     * @throws Exception
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">configure</span><span class="token punctuation">(</span><span class="token class-name">HttpSecurity</span> http<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 授权</span>
        http<span class="token punctuation">.</span><span class="token function">authorizeRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token comment">// 对于以下列出的所有路径</span>
                <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span>
                        <span class="token string">"/user/setting"</span><span class="token punctuation">,</span><span class="token comment">// 用户设置</span>
                        <span class="token string">"/user/upload"</span><span class="token punctuation">,</span><span class="token comment">// 用户文件上传</span>
                        <span class="token string">"/discuss/add"</span><span class="token punctuation">,</span><span class="token comment">// 帖子发布</span>
                        <span class="token string">"/comment/add/**"</span><span class="token punctuation">,</span><span class="token comment">// 评论发布</span>
                        <span class="token string">"/letter/**"</span><span class="token punctuation">,</span><span class="token comment">// 私信相关内容</span>
                        <span class="token string">"/notice/**"</span><span class="token punctuation">,</span><span class="token comment">// 通知相关内容</span>
                        <span class="token string">"/like"</span><span class="token punctuation">,</span><span class="token comment">// 点赞</span>
                        <span class="token string">"/follow"</span><span class="token punctuation">,</span><span class="token comment">// 加关注</span>
                        <span class="token string">"/unfollow"</span><span class="token comment">// 取消关注</span>
                <span class="token punctuation">)</span>
                <span class="token comment">// 只要有以下相关权限,都可以访问</span>
                <span class="token punctuation">.</span><span class="token function">hasAnyAuthority</span><span class="token punctuation">(</span>
                        AUTHORITY_USER<span class="token punctuation">,</span><span class="token comment">// 权限: 普通用户</span>
                        AUTHORITY_ADMIN<span class="token punctuation">,</span><span class="token comment">// 权限: 管理员</span>
                        AUTHORITY_MODERATOR<span class="token comment">// 权限: 版主</span>
                <span class="token punctuation">)</span>
                <span class="token comment">// 对于以下列出的所有路径</span>
                <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span>
                        <span class="token string">"/discuss/top"</span><span class="token punctuation">,</span>
                        <span class="token string">"/discuss/wonderful"</span>
                <span class="token punctuation">)</span>
                <span class="token comment">// 只有具有以下列出的权限才可以访问</span>
                <span class="token punctuation">.</span><span class="token function">hasAnyAuthority</span><span class="token punctuation">(</span>
                        AUTHORITY_MODERATOR<span class="token comment">// 权限: 版主</span>
                <span class="token punctuation">)</span>
                <span class="token comment">// 对于以下列出的所有路径</span>
                <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span>
                        <span class="token string">"/discuss/delete"</span><span class="token punctuation">,</span>
                        <span class="token string">"/data/**"</span>
                <span class="token punctuation">)</span>
                <span class="token comment">// 只有具有以下列出的权限才可以访问</span>
                <span class="token punctuation">.</span><span class="token function">hasAnyAuthority</span><span class="token punctuation">(</span>
                        AUTHORITY_ADMIN
                <span class="token punctuation">)</span>
                <span class="token comment">// 除了以上列出的权限限制约定外，其他请求路径都放行</span>
                <span class="token punctuation">.</span><span class="token function">anyRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token comment">//</span>
                <span class="token punctuation">.</span><span class="token function">and</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">csrf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">disable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 如果权限不够时的处理</span>
        http<span class="token punctuation">.</span><span class="token function">exceptionHandling</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token comment">// 没有登录时的处理</span>
                <span class="token punctuation">.</span><span class="token function">authenticationEntryPoint</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AuthenticationEntryPoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 没有登录</span>
                    <span class="token annotation punctuation">@Override</span>
                    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">commence</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span>
                                         <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span>
                                         <span class="token class-name">AuthenticationException</span> e<span class="token punctuation">)</span>
                            <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
                        <span class="token comment">// 如果请求x-requested-with 中头包含XMLHttpRequest 说明是异步请求</span>
                        <span class="token class-name">String</span> xRequestedWith <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getHeader</span><span class="token punctuation">(</span><span class="token string">"x-requested-with"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"XMLHttpRequest"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>xRequestedWith<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                            <span class="token comment">// 设置响应体是json 格式(因为是异步请求,所以返回内容要是json格式)</span>
                            response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"application/plain;charset=utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                            <span class="token comment">// 拿到输出流,输出返回内容给前端页面</span>
                            <span class="token class-name">PrintWriter</span> writer <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                            writer<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">,</span> <span class="token string">"你还没有登录哦!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><span class="token comment">// 不是异步请求</span>
                            <span class="token comment">// 重定向到登录页面</span>
                            response<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getContextPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/login"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span><span class="token punctuation">)</span>
                <span class="token comment">// 拒绝访问(权限不足时的处理)</span>
                <span class="token punctuation">.</span><span class="token function">accessDeniedHandler</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AccessDeniedHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 权限不足</span>
                    <span class="token annotation punctuation">@Override</span>
                    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">handle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span>
                                       <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span>
                                       <span class="token class-name">AccessDeniedException</span> e<span class="token punctuation">)</span>
                            <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
                        <span class="token class-name">String</span> xRequestedWith <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getHeader</span><span class="token punctuation">(</span><span class="token string">"x-requested-with"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"XMLHttpRequest"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>xRequestedWith<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                            <span class="token comment">// 设置响应体是json 格式(因为是异步请求,所以返回内容要是json格式)</span>
                            response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"application/plain;charset=utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                            <span class="token comment">// 拿到输出流,输出返回内容给前端页面</span>
                            <span class="token class-name">PrintWriter</span> writer <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                            writer<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">,</span> <span class="token string">"你没有访问此功能的权限!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><span class="token comment">// 不是异步请求</span>
                            <span class="token comment">// 重定向到没有权限页面</span>
                            response<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getContextPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/denied"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// Security底层默认会拦截/logout请求,进行退出处理.</span>
        <span class="token comment">// 覆盖它默认的逻辑,才能执行我们自己的退出代码.</span>
        http<span class="token punctuation">.</span><span class="token function">logout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">logoutUrl</span><span class="token punctuation">(</span><span class="token string">"/securitylogout"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="14-帖子的置顶、加精、删除"><a href="#14-帖子的置顶、加精、删除" class="headerlink" title="14. 帖子的置顶、加精、删除"></a>14. 帖子的置顶、加精、删除</h2><p>技术介绍：<strong>Thymleaf Extras SpringSecurity5</strong></p>
<p><img src="https://img-blog.csdnimg.cn/20201203120707254.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="14-1-引入依赖"><a href="#14-1-引入依赖" class="headerlink" title="14.1 引入依赖"></a>14.1 引入依赖</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mvnrepository<span class="token punctuation">.</span>com<span class="token operator">/</span>artifact<span class="token operator">/</span>org<span class="token punctuation">.</span>thymeleaf<span class="token punctuation">.</span>extras<span class="token operator">/</span>thymeleaf<span class="token operator">-</span>extras<span class="token operator">-</span>springsecurity5 <span class="token operator">--</span><span class="token operator">&gt;</span>
<span class="token generics"><span class="token punctuation">&lt;</span>dependency<span class="token punctuation">&gt;</span></span>
    <span class="token generics"><span class="token punctuation">&lt;</span>groupId<span class="token punctuation">&gt;</span></span>org<span class="token punctuation">.</span>thymeleaf<span class="token punctuation">.</span>extras<span class="token operator">&lt;</span><span class="token operator">/</span>groupId<span class="token operator">&gt;</span>
    <span class="token generics"><span class="token punctuation">&lt;</span>artifactId<span class="token punctuation">&gt;</span></span>thymeleaf<span class="token operator">-</span>extras<span class="token operator">-</span>springsecurity5<span class="token operator">&lt;</span><span class="token operator">/</span>artifactId<span class="token operator">&gt;</span>
    <span class="token generics"><span class="token punctuation">&lt;</span>version<span class="token punctuation">&gt;</span></span><span class="token number">3.0</span><span class="token number">.4</span><span class="token punctuation">.</span>RELEASE<span class="token operator">&lt;</span><span class="token operator">/</span>version<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>dependency<span class="token operator">&gt;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="14-2-DiscussPostController-中新增三个接口"><a href="#14-2-DiscussPostController-中新增三个接口" class="headerlink" title="14.2 DiscussPostController 中新增三个接口"></a>14.2 DiscussPostController 中新增三个接口</h3><p>对应Mapper 和 Service 层的修改直接看完整代码即可！</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * 帖子置顶操作
 *
 * @param id
 * @return
 */</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/top"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
<span class="token annotation punctuation">@ResponseBody</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">setTop</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    discussPostService<span class="token punctuation">.</span><span class="token function">updateType</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 触发发帖事件</span>
    <span class="token comment">// 帖子帖子后，触发事件：将刚帖子帖子的消息通知订阅的消费者</span>
    <span class="token comment">// 消费者在消费帖子类型事件时，会将帖子信息 传递到 ES 服务器存储/更新数据</span>
    <span class="token class-name">Event</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">setTopic</span><span class="token punctuation">(</span>TOPIC_PUBLISH<span class="token punctuation">)</span><span class="token comment">// 主题: 发帖</span>
            <span class="token punctuation">.</span><span class="token function">setUserId</span><span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 登录用户id</span>
            <span class="token punctuation">.</span><span class="token function">setEntityType</span><span class="token punctuation">(</span>ENTITY_TYPE_POST<span class="token punctuation">)</span><span class="token comment">// 实体类型: 帖子</span>
            <span class="token punctuation">.</span><span class="token function">setEntityId</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 实体id</span>
    eventProducer<span class="token punctuation">.</span><span class="token function">fireEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 帖子加精操作
 *
 * @param id
 * @return
 */</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/wonderful"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
<span class="token annotation punctuation">@ResponseBody</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">setWonderful</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    discussPostService<span class="token punctuation">.</span><span class="token function">updateStatus</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 触发发帖事件</span>
    <span class="token comment">// 加精帖子后，触发事件：将刚加精帖子的消息通知订阅的消费者</span>
    <span class="token comment">// 消费者在消费帖子类型事件时，会将帖子信息 传递到 ES 服务器存储/更新数据</span>
    <span class="token class-name">Event</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">setTopic</span><span class="token punctuation">(</span>TOPIC_PUBLISH<span class="token punctuation">)</span><span class="token comment">// 主题: 发帖</span>
            <span class="token punctuation">.</span><span class="token function">setUserId</span><span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 登录用户id</span>
            <span class="token punctuation">.</span><span class="token function">setEntityType</span><span class="token punctuation">(</span>ENTITY_TYPE_POST<span class="token punctuation">)</span><span class="token comment">// 实体类型: 帖子</span>
            <span class="token punctuation">.</span><span class="token function">setEntityId</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 实体id</span>
    eventProducer<span class="token punctuation">.</span><span class="token function">fireEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 帖子删除操作
 *
 * @param id
 * @return
 */</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/delete"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
<span class="token annotation punctuation">@ResponseBody</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">setDelete</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    discussPostService<span class="token punctuation">.</span><span class="token function">updateStatus</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 触发删帖事件</span>
    <span class="token comment">// 删除帖子后，触发事件：将刚删除帖子的消息通知订阅的消费者</span>
    <span class="token comment">// 消费者在消费帖子类型事件时，会将帖子信息 传递到 ES 服务器存储/更新数据</span>
    <span class="token class-name">Event</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">setTopic</span><span class="token punctuation">(</span>TOPIC_DELETE<span class="token punctuation">)</span><span class="token comment">// 主题: 删帖</span>
            <span class="token punctuation">.</span><span class="token function">setUserId</span><span class="token punctuation">(</span>hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 登录用户id</span>
            <span class="token punctuation">.</span><span class="token function">setEntityType</span><span class="token punctuation">(</span>ENTITY_TYPE_POST<span class="token punctuation">)</span><span class="token comment">// 实体类型: 帖子</span>
            <span class="token punctuation">.</span><span class="token function">setEntityId</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 实体id</span>
    eventProducer<span class="token punctuation">.</span><span class="token function">fireEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="14-3-效果展示"><a href="#14-3-效果展示" class="headerlink" title="14.3 效果展示"></a>14.3 效果展示</h3><p><img src="https://img-blog.csdnimg.cn/20201203125612471.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h2 id="15-网站数据统计"><a href="#15-网站数据统计" class="headerlink" title="15. 网站数据统计"></a>15. 网站数据统计</h2><p><img src="https://img-blog.csdnimg.cn/202012031756035.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<blockquote>
<p>声明：<strong>HyperLogLog</strong> 和 <strong>Bitmap</strong> 都是 Redis 中的高级数据类型！</p>
</blockquote>
<h3 id="15-1-RedisKeyUtil-中添加行营的key-和方法"><a href="#15-1-RedisKeyUtil-中添加行营的key-和方法" class="headerlink" title="15.1 RedisKeyUtil 中添加行营的key 和方法"></a>15.1 RedisKeyUtil 中添加行营的key 和方法</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_UV <span class="token operator">=</span> <span class="token string">"uv"</span><span class="token punctuation">;</span><span class="token comment">// 独立访客(通过用户IP地址排重统计)</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> PREFIX_DAU <span class="token operator">=</span> <span class="token string">"dau"</span><span class="token punctuation">;</span><span class="token comment">// 日活跃用户(通过ID排重统计)</span>

<span class="token comment">/**
 * 获取单日UV集合(HyperLogLog)的key
 * @param date
 * @return
 */</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getUVKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> date<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> PREFIX_UV <span class="token operator">+</span> SPLIT <span class="token operator">+</span> date<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 获取区间UV(两个日期之间统计的UV)集合(HyperLogLog)的key
 * @param startDate
 * @param endDate
 * @return
 */</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getUVKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> startDate<span class="token punctuation">,</span> <span class="token class-name">String</span> endDate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> PREFIX_UV <span class="token operator">+</span> SPLIT <span class="token operator">+</span> startDate <span class="token operator">+</span> SPLIT <span class="token operator">+</span> endDate<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 获取单日活跃用户集合(Bitmap)的key
 * @param date
 * @return
 */</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getDAUKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> date<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> PREFIX_DAU <span class="token operator">+</span> SPLIT <span class="token operator">+</span> date<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 获取区间活跃用户(两个日期之间统计的活跃用户)集合(Bitmap)的key
 * @param startDate
 * @param endDate
 * @return
 */</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getDAUKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> startDate<span class="token punctuation">,</span> <span class="token class-name">String</span> endDate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> PREFIX_DAU <span class="token operator">+</span> SPLIT <span class="token operator">+</span> startDate <span class="token operator">+</span> SPLIT <span class="token operator">+</span> endDate<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="15-2-DataService"><a href="#15-2-DataService" class="headerlink" title="15.2 DataService"></a>15.2 DataService</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/03/18:05
 * @Description: 网站数据统计相关的Service
 */</span>
<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DataService</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token class-name">SimpleDateFormat</span> simpleDateFormat <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleDateFormat</span><span class="token punctuation">(</span><span class="token string">"yyyyMMdd"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 将指定的IP计入UV
     *
     * @param ip
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">recordUV</span><span class="token punctuation">(</span><span class="token class-name">String</span> ip<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取单日UV集合(HyperLogLog)的key</span>
        <span class="token class-name">String</span> redisKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getUVKey</span><span class="token punctuation">(</span>simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 将数据记录到指定redisKey的HyperLogLog中</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">opsForHyperLogLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>redisKey<span class="token punctuation">,</span> ip<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 统计指定日期时间段范围内的UV
     *
     * @param start
     * @param end
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">long</span> <span class="token function">calculateUV</span><span class="token punctuation">(</span><span class="token class-name">Date</span> start<span class="token punctuation">,</span> <span class="token class-name">Date</span> end<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>start <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> end <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"参数不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// keyList 用于整理该日期范围内的key</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> keyList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// Calendar 用于对日期进行运算</span>
        <span class="token class-name">Calendar</span> calendar <span class="token operator">=</span> <span class="token class-name">Calendar</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        calendar<span class="token punctuation">.</span><span class="token function">setTime</span><span class="token punctuation">(</span>start<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// !calendar.getTime().after(end) 当前时间的不晚于 end的时间时,进行while循环</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>calendar<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span>end<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 获取单日UV集合(HyperLogLog)的key</span>
            <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getUVKey</span><span class="token punctuation">(</span>simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>calendar<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 将key 存入集合</span>
            keyList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 日期时间向后推一天</span>
            calendar<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">Calendar</span><span class="token punctuation">.</span>DATE<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 获取区间UV(两个日期之间统计的UV)集合(HyperLogLog)的key</span>
        <span class="token class-name">String</span> redisKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getUVKey</span><span class="token punctuation">(</span>simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>start<span class="token punctuation">)</span><span class="token punctuation">,</span> simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>end<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 合并redisKey对应的HyperLogLog集合和keyList集合</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">opsForHyperLogLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">union</span><span class="token punctuation">(</span>redisKey<span class="token punctuation">,</span> keyList<span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 返回HyperLogLog中统计的数量</span>
        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForHyperLogLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span>redisKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 将指定用户计入DAU
     *
     * @param userId
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">recordDAU</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取单日活跃用户集合(Bitmap)的key</span>
        <span class="token class-name">String</span> redisKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getDAUKey</span><span class="token punctuation">(</span>simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 将数据记录到指定redisKey的Bitmap中,第三个参数表示是否活跃,true表示活跃</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setBit</span><span class="token punctuation">(</span>redisKey<span class="token punctuation">,</span> userId<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 统计指定日期范围内的DAU
     *
     * @param start
     * @param end
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">long</span> <span class="token function">calculateDAU</span><span class="token punctuation">(</span><span class="token class-name">Date</span> start<span class="token punctuation">,</span> <span class="token class-name">Date</span> end<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>start <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> end <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"参数不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// keyList 用于整理该日期范围内的key</span>
        <span class="token class-name">List</span><span class="token operator">&lt;</span><span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> keyList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// Calendar 用于对日期进行运算</span>
        <span class="token class-name">Calendar</span> calendar <span class="token operator">=</span> <span class="token class-name">Calendar</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        calendar<span class="token punctuation">.</span><span class="token function">setTime</span><span class="token punctuation">(</span>start<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// !calendar.getTime().after(end) 当前时间的不晚于 end的时间时,进行while循环</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>calendar<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span>end<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 获取单日活跃用户集合(Bitmap)的key</span>
            <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getDAUKey</span><span class="token punctuation">(</span>simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>calendar<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 将key 存入集合(参数为key的byte数组)</span>
            keyList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 日期时间向后推一天</span>
            calendar<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">Calendar</span><span class="token punctuation">.</span>DATE<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 进行OR运算</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span> redisTemplate<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RedisCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">doInRedis</span><span class="token punctuation">(</span><span class="token class-name">RedisConnection</span> connection<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">DataAccessException</span> <span class="token punctuation">{</span>
                <span class="token class-name">String</span> redisKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getDAUKey</span><span class="token punctuation">(</span>simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>start<span class="token punctuation">)</span><span class="token punctuation">,</span>
                                                         simpleDateFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>end<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                connection<span class="token punctuation">.</span><span class="token function">bitOp</span><span class="token punctuation">(</span><span class="token class-name">RedisStringCommands<span class="token punctuation">.</span>BitOperation</span><span class="token punctuation">.</span>OR<span class="token punctuation">,</span>
                        redisKey<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> keyList<span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> connection<span class="token punctuation">.</span><span class="token function">bitCount</span><span class="token punctuation">(</span>redisKey<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="15-3-使用DataInterceptor拦截器来做访客统计"><a href="#15-3-使用DataInterceptor拦截器来做访客统计" class="headerlink" title="15.3 使用DataInterceptor拦截器来做访客统计"></a>15.3 使用DataInterceptor拦截器来做访客统计</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/03/18:34
 * @Description: 访问统计UV(独立访客)/DAI(日活跃用户)的拦截器
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DataInterceptor</span> <span class="token keyword">implements</span> <span class="token class-name">HandlerInterceptor</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DataService</span> dataService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">HostHolder</span> hostHolder<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">preHandle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span>
                             <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span>
                             <span class="token class-name">Object</span> handler<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 统计UV(独立访客)</span>
        <span class="token comment">// 获得访客的IP</span>
        <span class="token class-name">String</span> ip <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getRemoteHost</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 将指定的IP计入UV</span>
        dataService<span class="token punctuation">.</span><span class="token function">recordUV</span><span class="token punctuation">(</span>ip<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 统计DAU(日活跃用户)</span>
        <span class="token comment">// 获取登录用户对象</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> hostHolder<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>user <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 将指定用户计入DAU</span>
            dataService<span class="token punctuation">.</span><span class="token function">recordDAU</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>拦截器写好后，将其注册的 <strong>WebMvcConfig</strong> 中去！</p>
<h2 id="16-任务执行和任务调度"><a href="#16-任务执行和任务调度" class="headerlink" title="16. 任务执行和任务调度"></a>16. 任务执行和任务调度</h2><blockquote>
<p>实现方式可以选择以下三种方式</p>
</blockquote>
<ul>
<li><strong>JDK</strong> 线程池<ul>
<li><code>ExecutorService</code></li>
<li><code>ScheduledExecutorService</code></li>
</ul>
</li>
<li><strong>Spring</strong> 线程池<ul>
<li><code>ThreadPoolTaskExecutor</code></li>
<li><code>ThreadPoolTaskScheduler</code></li>
</ul>
</li>
<li>分布式定时任务<ul>
<li><code>Spring Quartz</code></li>
</ul>
</li>
</ul>
<h3 id="16-1-数据库sql"><a href="#16-1-数据库sql" class="headerlink" title="16.1 数据库sql"></a>16.1 数据库sql</h3><pre class="line-numbers language-sql" data-language="sql"><code class="language-sql"><span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_PAUSED_TRIGGER_GRPS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_SCHEDULER_STATE<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_LOCKS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_SIMPLE_TRIGGERS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_SIMPROP_TRIGGERS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_CRON_TRIGGERS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_BLOB_TRIGGERS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_TRIGGERS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_JOB_DETAILS<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> QRTZ_CALENDARS<span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_JOB_DETAILS<span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
DESCRIPTION <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">250</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_CLASS_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">250</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
IS_DURABLE <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
IS_NONCONCURRENT <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
IS_UPDATE_DATA <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
REQUESTS_RECOVERY <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_DATA <span class="token keyword">BLOB</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_TRIGGERS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
DESCRIPTION <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">250</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
NEXT_FIRE_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
PREV_FIRE_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
PRIORITY <span class="token keyword">INTEGER</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_STATE <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_TYPE <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
START_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
END_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
CALENDAR_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
MISFIRE_INSTR <span class="token keyword">SMALLINT</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_DATA <span class="token keyword">BLOB</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">FOREIGN</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span>
<span class="token keyword">REFERENCES</span> QRTZ_JOB_DETAILS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_SIMPLE_TRIGGERS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
REPEAT_COUNT <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
REPEAT_INTERVAL <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">12</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TIMES_TRIGGERED <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">FOREIGN</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span>
<span class="token keyword">REFERENCES</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_CRON_TRIGGERS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
CRON_EXPRESSION <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TIME_ZONE_ID <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">80</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">FOREIGN</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span>
<span class="token keyword">REFERENCES</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_SIMPROP_TRIGGERS
  <span class="token punctuation">(</span>
    SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    TRIGGER_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    STR_PROP_1 <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">512</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    STR_PROP_2 <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">512</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    STR_PROP_3 <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">512</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    INT_PROP_1 <span class="token keyword">INT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    INT_PROP_2 <span class="token keyword">INT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    LONG_PROP_1 <span class="token keyword">BIGINT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    LONG_PROP_2 <span class="token keyword">BIGINT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    DEC_PROP_1 <span class="token keyword">NUMERIC</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    DEC_PROP_2 <span class="token keyword">NUMERIC</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    BOOL_PROP_1 <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    BOOL_PROP_2 <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token keyword">FOREIGN</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span>
    <span class="token keyword">REFERENCES</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_BLOB_TRIGGERS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
BLOB_DATA <span class="token keyword">BLOB</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">INDEX</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span> TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">FOREIGN</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span>
<span class="token keyword">REFERENCES</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_CALENDARS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
CALENDAR_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
CALENDAR <span class="token keyword">BLOB</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>CALENDAR_NAME<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_PAUSED_TRIGGER_GRPS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_FIRED_TRIGGERS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
ENTRY_ID <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">95</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
TRIGGER_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
INSTANCE_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
FIRED_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
SCHED_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
PRIORITY <span class="token keyword">INTEGER</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
STATE <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
JOB_GROUP <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
IS_NONCONCURRENT <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
REQUESTS_RECOVERY <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>ENTRY_ID<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_SCHEDULER_STATE <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
INSTANCE_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">190</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
LAST_CHECKIN_TIME <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
CHECKIN_INTERVAL <span class="token keyword">BIGINT</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>INSTANCE_NAME<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> QRTZ_LOCKS <span class="token punctuation">(</span>
SCHED_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
LOCK_NAME <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">40</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span>
<span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>LOCK_NAME<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_J_REQ_RECOVERY <span class="token keyword">ON</span> QRTZ_JOB_DETAILS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>REQUESTS_RECOVERY<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_J_GRP <span class="token keyword">ON</span> QRTZ_JOB_DETAILS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_J <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_JG <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_C <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>CALENDAR_NAME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_G <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_STATE <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_STATE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_N_STATE <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">,</span>TRIGGER_STATE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_N_G_STATE <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">,</span>TRIGGER_STATE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_NEXT_FIRE_TIME <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>NEXT_FIRE_TIME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_NFT_ST <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_STATE<span class="token punctuation">,</span>NEXT_FIRE_TIME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_NFT_MISFIRE <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>MISFIRE_INSTR<span class="token punctuation">,</span>NEXT_FIRE_TIME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_NFT_ST_MISFIRE <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>MISFIRE_INSTR<span class="token punctuation">,</span>NEXT_FIRE_TIME<span class="token punctuation">,</span>TRIGGER_STATE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_T_NFT_ST_MISFIRE_GRP <span class="token keyword">ON</span> QRTZ_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>MISFIRE_INSTR<span class="token punctuation">,</span>NEXT_FIRE_TIME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">,</span>TRIGGER_STATE<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_FT_TRIG_INST_NAME <span class="token keyword">ON</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>INSTANCE_NAME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_FT_INST_JOB_REQ_RCVRY <span class="token keyword">ON</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>INSTANCE_NAME<span class="token punctuation">,</span>REQUESTS_RECOVERY<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_FT_J_G <span class="token keyword">ON</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_FT_JG <span class="token keyword">ON</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>JOB_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_FT_T_G <span class="token keyword">ON</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">CREATE</span> <span class="token keyword">INDEX</span> IDX_QRTZ_FT_TG <span class="token keyword">ON</span> QRTZ_FIRED_TRIGGERS<span class="token punctuation">(</span>SCHED_NAME<span class="token punctuation">,</span>TRIGGER_GROUP<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">commit</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="16-2-application-properties-中配置-quartz"><a href="#16-2-application-properties-中配置-quartz" class="headerlink" title="16.2 application.properties 中配置 quartz"></a>16.2 application.properties 中配置 quartz</h3><pre class="line-numbers language-properties" data-language="properties"><code class="language-properties"><span class="token comment"># QuartzProperties</span>
<span class="token comment"># quartz 分布式定时任务调度相关配置</span>
<span class="token attr-name">spring.quartz.job-store-type</span><span class="token punctuation">=</span><span class="token attr-value">jdbc</span>
<span class="token attr-name">spring.quartz.scheduler-name</span><span class="token punctuation">=</span><span class="token attr-value">communityScheduler</span>
<span class="token attr-name">spring.quartz.properties.org.quartz.scheduler.instanceId</span><span class="token punctuation">=</span><span class="token attr-value">AUTO</span>
<span class="token attr-name">spring.quartz.properties.org.quartz.jobStore.class</span><span class="token punctuation">=</span><span class="token attr-value">org.quartz.impl.jdbcjobstore.JobStoreTX</span>
<span class="token attr-name">spring.quartz.properties.org.quartz.jobStore.driverDelegateClass</span><span class="token punctuation">=</span><span class="token attr-value">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</span>
<span class="token attr-name">spring.quartz.properties.org.quartz.jobStore.isClustered</span><span class="token punctuation">=</span><span class="token attr-value">true</span>
<span class="token attr-name">spring.quartz.properties.org.quartz.threadPool.class</span><span class="token punctuation">=</span><span class="token attr-value">org.quartz.simpl.SimpleThreadPool</span>
<span class="token attr-name">spring.quartz.properties.org.quartz.threadPool.threadCount</span><span class="token punctuation">=</span><span class="token attr-value">5</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="16-3-PostScoreRefreshJob定时任务类"><a href="#16-3-PostScoreRefreshJob定时任务类" class="headerlink" title="16.3 PostScoreRefreshJob定时任务类"></a>16.3 PostScoreRefreshJob定时任务类</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/04/16:08
 * @Description: 定时任务类(要实现Job接口)
 */</span>
<span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/04/16:08
 * @Description: 定时任务类(要实现Job接口)
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AlphaJob</span> <span class="token keyword">implements</span> <span class="token class-name">Job</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">JobExecutionContext</span> context<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">JobExecutionException</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">": execute a quartz job..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="16-4-QuartzConfig-配置类"><a href="#16-4-QuartzConfig-配置类" class="headerlink" title="16.4 QuartzConfig 配置类"></a>16.4 QuartzConfig 配置类</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/04/16:05
 * @Description: quartz 分布式定时任务调度相关配置类
 * &lt;p&gt;
 * 作用：
 * 1. -&gt; 仅仅当第一次访问时读取该配置
 * 2. -&gt; 并将该配置封装的信息初始化到数据库数据库
 * 3. -&gt; 以后每次quartz是访问数据去调用,而不再访问该配置类！
 */</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">QuartzConfig</span> <span class="token punctuation">{</span>

    <span class="token comment">/**
     * FactoryBean可简化Bean的实例化过程:
     * &lt;p&gt;
     * 1.通过FactoryBean封装Bean的实例化过程.
     * 2.将FactoryBean装配到Spring容器里.
     * 3.将FactoryBean注入给其他的Bean.
     * 4.该Bean得到的是FactoryBean所管理的对象实例.
     */</span>

    <span class="token comment">// 配置JobDetail</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">JobDetailFactoryBean</span> <span class="token function">alphaJobDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">JobDetailFactoryBean</span> factoryBean <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JobDetailFactoryBean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setJobClass</span><span class="token punctuation">(</span><span class="token class-name">AlphaJob</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">"alphaJob"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setGroup</span><span class="token punctuation">(</span><span class="token string">"alphaJobGroup"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setDurability</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setRequestsRecovery</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> factoryBean<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 配置Trigger(SimpleTriggerFactoryBean, CronTriggerFactoryBean)</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">SimpleTriggerFactoryBean</span> <span class="token function">alphaTrigger</span><span class="token punctuation">(</span><span class="token class-name">JobDetail</span> alphaJobDetail<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SimpleTriggerFactoryBean</span> factoryBean <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleTriggerFactoryBean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setJobDetail</span><span class="token punctuation">(</span>alphaJobDetail<span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">"alphaTrigger"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setGroup</span><span class="token punctuation">(</span><span class="token string">"alphaTriggerGroup"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setRepeatInterval</span><span class="token punctuation">(</span><span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        factoryBean<span class="token punctuation">.</span><span class="token function">setJobDataMap</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">JobDataMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> factoryBean<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="17-热帖排行"><a href="#17-热帖排行" class="headerlink" title="17. 热帖排行"></a>17. 热帖排行</h2><p><img src="https://img-blog.csdnimg.cn/20201204164138799.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="17-1-PostScoreRefreshJob"><a href="#17-1-PostScoreRefreshJob" class="headerlink" title="17.1 PostScoreRefreshJob"></a>17.1 PostScoreRefreshJob</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/04/18:48
 * @Description: 作用：定时对帖子分数进行刷新
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PostScoreRefreshJob</span> <span class="token keyword">implements</span> <span class="token class-name">Job</span><span class="token punctuation">,</span> <span class="token class-name">CommunityConstant</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">PostScoreRefreshJob</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DiscussPostService</span> discussPostService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">LikeService</span> likeService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">ElasticSearchService</span> elasticSearchService<span class="token punctuation">;</span>

    <span class="token comment">// 牛客纪元(常量)</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Date</span> epoch<span class="token punctuation">;</span>

    <span class="token comment">// 静态代码块，随着类的加载而加载</span>
    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            epoch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleDateFormat</span><span class="token punctuation">(</span><span class="token string">"yyyy-MM-dd HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">"2020-11-11 00:00:00"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ParseException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"初始化牛客纪元失败!"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 定时任务：定时对帖子分数进行刷新
     * @param context
     * @throws JobExecutionException
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">JobExecutionContext</span> context<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">JobExecutionException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取帖子分数集合的key</span>
        <span class="token class-name">String</span> redisKey <span class="token operator">=</span> <span class="token class-name">RedisKeyUtil</span><span class="token punctuation">.</span><span class="token function">getPostScoreKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">BoundSetOperations</span> operations <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">boundSetOps</span><span class="token punctuation">(</span>redisKey<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>operations<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"[任务取消] 没有需要刷新的帖子!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"[任务开始] 正在刷新帖子分数: "</span> <span class="token operator">+</span> operations<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span>operations<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 批量从 operations 弹出帖子id,并刷新计算帖子的分数,直到operations=0结束</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">)</span> operations<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"[任务结束] 帖子分数刷新完毕!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 刷新计算帖子分数的方法</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">refresh</span><span class="token punctuation">(</span><span class="token keyword">int</span> postId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">DiscussPost</span> post <span class="token operator">=</span> discussPostService<span class="token punctuation">.</span><span class="token function">findDiscussPostById</span><span class="token punctuation">(</span>postId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>post <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"该帖子不存在: id = "</span> <span class="token operator">+</span> postId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 是否精华</span>
        <span class="token keyword">boolean</span> wonderful <span class="token operator">=</span> post<span class="token punctuation">.</span><span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token comment">// 评论数量</span>
        <span class="token keyword">int</span> commentCount <span class="token operator">=</span> post<span class="token punctuation">.</span><span class="token function">getCommentCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 点赞数量</span>
        <span class="token keyword">long</span> likeCount <span class="token operator">=</span> likeService<span class="token punctuation">.</span><span class="token function">findEntityLikeCount</span><span class="token punctuation">(</span>ENTITY_TYPE_POST<span class="token punctuation">,</span> postId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 计算权重</span>
        <span class="token keyword">double</span> w <span class="token operator">=</span> <span class="token punctuation">(</span>wonderful <span class="token operator">?</span> <span class="token number">75</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">+</span> commentCount <span class="token operator">*</span> <span class="token number">10</span> <span class="token operator">+</span> likeCount <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span>
        <span class="token comment">// 分数 = 帖子权重 + 距离牛客纪元的天数</span>
        <span class="token keyword">double</span> score <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">log10</span><span class="token punctuation">(</span><span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token operator">+</span> <span class="token punctuation">(</span>post<span class="token punctuation">.</span><span class="token function">getCreateTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> epoch<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">(</span><span class="token number">1000</span> <span class="token operator">*</span> <span class="token number">3600</span> <span class="token operator">*</span> <span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 更新帖子分数</span>
        discussPostService<span class="token punctuation">.</span><span class="token function">updateScore</span><span class="token punctuation">(</span>postId<span class="token punctuation">,</span> score<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 同步ES中的搜索数据</span>
        post<span class="token punctuation">.</span><span class="token function">setScore</span><span class="token punctuation">(</span>score<span class="token punctuation">)</span><span class="token punctuation">;</span>
        elasticSearchService<span class="token punctuation">.</span><span class="token function">saveDiscussPost</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="18-生成长图"><a href="#18-生成长图" class="headerlink" title="18.生成长图"></a>18.生成长图</h2><p><img src="https://img-blog.csdnimg.cn/20201204200107371.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<ul>
<li><p>使用工具：<strong>tkhtmltopdf</strong></p>
</li>
<li><p>官网下载地址：<a target="_blank" rel="noopener" href="https://wkhtmltopdf.org/downloads.html">https://wkhtmltopdf.org/downloads.html</a> </p>
</li>
<li><p>入门介绍参考文章：<a target="_blank" rel="noopener" href="https://csp1999.blog.csdn.net/article/details/110716381">wkhtmltopdf工具将网站转换成pdf或图片</a></p>
</li>
</ul>
<h3 id="18-1-ShareController"><a href="#18-1-ShareController" class="headerlink" title="18.1 ShareController"></a>18.1 ShareController</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * @Auther: csp1999
 * @Date: 2020/12/05/19:41
 * @Description: 图片生成并分享
 */</span>
<span class="token annotation punctuation">@Controller</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ShareController</span> <span class="token keyword">implements</span> <span class="token class-name">CommunityConstant</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">ShareController</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">EventProducer</span> eventProducer<span class="token punctuation">;</span>

    <span class="token comment">// 项目域名</span>
    <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${community.path}"</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> path<span class="token punctuation">;</span>

    <span class="token comment">// 项目名称</span>
    <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${server.servlet.context-path}"</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> contextPath<span class="token punctuation">;</span>

    <span class="token comment">// 图片存储地址</span>
    <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${wk.image.storage}"</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> wkImageStorage<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 分享操作
     * @param htmlUrl
     * @return
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/share"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@ResponseBody</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">share</span><span class="token punctuation">(</span><span class="token class-name">String</span> htmlUrl<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 文件名</span>
        <span class="token class-name">String</span> fileName <span class="token operator">=</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">generateUUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// kafka 消息生产者通知消息消费者异步生成长图</span>
        <span class="token class-name">Event</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">setTopic</span><span class="token punctuation">(</span>TOPIC_SHARE<span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">"htmlUrl"</span><span class="token punctuation">,</span> htmlUrl<span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">"fileName"</span><span class="token punctuation">,</span> fileName<span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">"suffix"</span><span class="token punctuation">,</span> <span class="token string">".png"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        eventProducer<span class="token punctuation">.</span><span class="token function">fireEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 返回的访问路径放入map</span>
        <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"shareUrl"</span><span class="token punctuation">,</span> path <span class="token operator">+</span> contextPath <span class="token operator">+</span> <span class="token string">"/share/image/"</span> <span class="token operator">+</span> fileName<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token class-name">CommunityUtil</span><span class="token punctuation">.</span><span class="token function">getJSONString</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> map<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取长图
     * @param fileName
     * @param response
     */</span>
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">"/share/image/{fileName}"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">getShareImage</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">"fileName"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> fileName<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">isBlank</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"文件名不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"image/png"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">File</span> file <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">File</span><span class="token punctuation">(</span>wkImageStorage <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> fileName <span class="token operator">+</span> <span class="token string">".png"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">OutputStream</span> os <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">FileInputStream</span> fis <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> buffer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token number">1024</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>b <span class="token operator">=</span> fis<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span>buffer<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                os<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>buffer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"获取长图失败: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="18-2-在Kafka-事件消费者中添加如下代码"><a href="#18-2-在Kafka-事件消费者中添加如下代码" class="headerlink" title="18.2 在Kafka 事件消费者中添加如下代码"></a>18.2 在Kafka 事件消费者中添加如下代码</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// wk 工具的路径(生成图片)</span>
<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${wk.image.command}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> wkImageCommand<span class="token punctuation">;</span>
<span class="token comment">// 图片存储位置</span>
<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${wk.image.storage}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> wkImageStorage<span class="token punctuation">;</span>

<span class="token comment">/**
 * 消费图片分享事件
 *
 * @param record
 */</span>
<span class="token annotation punctuation">@KafkaListener</span><span class="token punctuation">(</span>topics <span class="token operator">=</span> TOPIC_SHARE<span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">handleShareMessage</span><span class="token punctuation">(</span><span class="token class-name">ConsumerRecord</span> <span class="token keyword">record</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">record</span> <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token keyword">record</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"消息的内容为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token class-name">Event</span> event <span class="token operator">=</span> <span class="token class-name">JSONObject</span><span class="token punctuation">.</span><span class="token function">parseObject</span><span class="token punctuation">(</span><span class="token keyword">record</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Event</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"消息格式错误!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token class-name">String</span> htmlUrl <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> event<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"htmlUrl"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> fileName <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> event<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"fileName"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> suffix <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> event<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"suffix"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// cmd 命令</span>
    <span class="token class-name">String</span> cmd <span class="token operator">=</span> wkImageCommand <span class="token operator">+</span> <span class="token string">" --quality 75 "</span>
            <span class="token operator">+</span> htmlUrl <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> wkImageStorage <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> fileName <span class="token operator">+</span> suffix<span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">// 操作系统执行cmd 命令</span>
        <span class="token class-name">Runtime</span><span class="token punctuation">.</span><span class="token function">getRuntime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span>cmd<span class="token punctuation">)</span><span class="token punctuation">;</span>
        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"生成长图成功: "</span> <span class="token operator">+</span> cmd<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"生成长图失败: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="18-3-测试生成长图"><a href="#18-3-测试生成长图" class="headerlink" title="18.3 测试生成长图"></a>18.3 测试生成长图</h3><p>我们测试执行：<a href="">http://localhost:8080/community/share?htmlUrl=https://www.baidu.com</a>，得到如下结果：</p>
<p><img src="https://img-blog.csdnimg.cn/2020120520115741.png" alt="在这里插入图片描述"></p>
<p>我们通过访问该返回的图片路径测试，可以得到该图片：</p>
<p><img src="https://img-blog.csdnimg.cn/20201205201242754.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<p>本地目录中查看生成的图片：</p>
<p><img src="https://img-blog.csdnimg.cn/20201205201331112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h2 id="19-项目性能优化"><a href="#19-项目性能优化" class="headerlink" title="19. 项目性能优化"></a>19. 项目性能优化</h2><p><img src="https://img-blog.csdnimg.cn/20201206114720407.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="19-1-pom-xml导入caffeine依赖"><a href="#19-1-pom-xml导入caffeine依赖" class="headerlink" title="19.1 pom.xml导入caffeine依赖"></a>19.1 pom.xml导入caffeine依赖</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mvnrepository<span class="token punctuation">.</span>com<span class="token operator">/</span>artifact<span class="token operator">/</span>com<span class="token punctuation">.</span>github<span class="token punctuation">.</span>ben<span class="token operator">-</span>manes<span class="token punctuation">.</span>caffeine<span class="token operator">/</span>caffeine <span class="token operator">--</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span>caffeine<span class="token operator">--</span><span class="token operator">&gt;</span>
<span class="token generics"><span class="token punctuation">&lt;</span>dependency<span class="token punctuation">&gt;</span></span>
    <span class="token generics"><span class="token punctuation">&lt;</span>groupId<span class="token punctuation">&gt;</span></span>com<span class="token punctuation">.</span>github<span class="token punctuation">.</span>ben<span class="token operator">-</span>manes<span class="token punctuation">.</span>caffeine<span class="token operator">&lt;</span><span class="token operator">/</span>groupId<span class="token operator">&gt;</span>
    <span class="token generics"><span class="token punctuation">&lt;</span>artifactId<span class="token punctuation">&gt;</span></span>caffeine<span class="token operator">&lt;</span><span class="token operator">/</span>artifactId<span class="token operator">&gt;</span>
    <span class="token generics"><span class="token punctuation">&lt;</span>version<span class="token punctuation">&gt;</span></span><span class="token number">2.7</span><span class="token number">.0</span><span class="token operator">&lt;</span><span class="token operator">/</span>version<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>dependency<span class="token operator">&gt;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="19-2-application-properties-配置文件中添加配置"><a href="#19-2-application-properties-配置文件中添加配置" class="headerlink" title="19.2 application.properties 配置文件中添加配置"></a>19.2 application.properties 配置文件中添加配置</h3><pre class="line-numbers language-properties" data-language="properties"><code class="language-properties"><span class="token comment"># caffeine 本地缓存相关配置</span>
<span class="token comment"># 缓存的帖子列表(max-size:表示本地缓存空间内最多能缓存的数据条数 15条)</span>
<span class="token attr-name">caffeine.posts.max-size</span><span class="token punctuation">=</span><span class="token attr-value">15</span>
<span class="token comment"># 缓存的帖子列表(expire-seconds:表示本地缓存数据的过期时间 180s)</span>
<span class="token attr-name">caffeine.posts.expire-seconds</span><span class="token punctuation">=</span><span class="token attr-value">180</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="19-3-优化Service层相关的代码"><a href="#19-3-优化Service层相关的代码" class="headerlink" title="19.3 优化Service层相关的代码"></a>19.3 优化Service层相关的代码</h3><p>为Service层相关的代码加上本地缓存：</p>
<p><strong>DiscussPostService</strong> 中添加缓存相关代码</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${caffeine.posts.max-size}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> caffeineCacheMaxSize<span class="token punctuation">;</span><span class="token comment">// 最大本地缓存数据的条数</span>

<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${caffeine.posts.expire-seconds}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> caffeineCacheExpireSeconds<span class="token punctuation">;</span><span class="token comment">// 本地缓存数据的过期时间</span>

<span class="token comment">/**
 * Caffeine 核心接口：Cache , LoadingCache , AsyncLoadingCache
 */</span>
<span class="token comment">// 帖子列表缓存</span>
<span class="token keyword">private</span> <span class="token class-name">LoadingCache</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">DiscussPost</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> discussPostListCache<span class="token punctuation">;</span>

<span class="token comment">// 帖子总数缓存</span>
<span class="token keyword">private</span> <span class="token class-name">LoadingCache</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> discussPostRowsCache<span class="token punctuation">;</span>

<span class="token comment">/**
 * 当该类被实例化或者被调用时,
 * 该init() 方法在构造函数以及@Autowired 之后执行
 */</span>
<span class="token annotation punctuation">@PostConstruct</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 初始化帖子列表缓存</span>
    discussPostListCache <span class="token operator">=</span> <span class="token class-name">Caffeine</span><span class="token punctuation">.</span><span class="token function">newBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token comment">// 最大本地缓存数据的条数</span>
            <span class="token punctuation">.</span><span class="token function">maximumSize</span><span class="token punctuation">(</span>caffeineCacheMaxSize<span class="token punctuation">)</span>
            <span class="token comment">// 本地缓存数据的过期时间</span>
            <span class="token punctuation">.</span><span class="token function">expireAfterWrite</span><span class="token punctuation">(</span>caffeineCacheExpireSeconds<span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span>SECONDS<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CacheLoader</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">DiscussPost</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token annotation punctuation">@Override</span>
                <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">DiscussPost</span><span class="token punctuation">&gt;</span></span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token annotation punctuation">@NonNull</span> <span class="token class-name">String</span> key<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 判断获取缓存的key 是否为空</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>key <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> key<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"key为空..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                    <span class="token comment">// 分割key 获得参数(limit 和 offset)</span>
                    <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> params <span class="token operator">=</span> key<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">":"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>params <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> params<span class="token punctuation">.</span>length <span class="token operator">!=</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"参数错误..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                    <span class="token keyword">int</span> offset <span class="token operator">=</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">int</span> limit <span class="token operator">=</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token comment">// 扩展：可以自己再加一个二级缓存 Redis -&gt; Mysql</span>
                    <span class="token comment">// 从数据库查数据,获取后将数据放入本地缓存</span>
                    logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"从DB中获取帖子列表数据..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">return</span> discussPostMapper<span class="token punctuation">.</span><span class="token function">selectDiscussPosts</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> offset<span class="token punctuation">,</span> limit<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 初始化帖子总数缓存</span>
    discussPostRowsCache <span class="token operator">=</span> <span class="token class-name">Caffeine</span><span class="token punctuation">.</span><span class="token function">newBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token comment">// 最大本地缓存数据的条数</span>
            <span class="token punctuation">.</span><span class="token function">maximumSize</span><span class="token punctuation">(</span>caffeineCacheMaxSize<span class="token punctuation">)</span>
            <span class="token comment">// 本地缓存数据的过期时间</span>
            <span class="token punctuation">.</span><span class="token function">expireAfterWrite</span><span class="token punctuation">(</span>caffeineCacheExpireSeconds<span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span>SECONDS<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CacheLoader</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token annotation punctuation">@Override</span>
                <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Integer</span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Integer</span> key<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 从数据库查数据,获取后将数据放入本地缓存</span>
                    logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"从DB中获取帖子总数量..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">return</span> discussPostMapper<span class="token punctuation">.</span><span class="token function">selectDiscussPostRows</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 查询用户发布的所有帖子(分页)
 *
 * @param userId 用户id
 * @param offset 起始位置
 * @param limit  每一页的数量
 * @return
 */</span>
<span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">DiscussPost</span><span class="token punctuation">&gt;</span></span> <span class="token function">findDiscussPosts</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">,</span> <span class="token keyword">int</span> offset<span class="token punctuation">,</span> <span class="token keyword">int</span> limit<span class="token punctuation">,</span>
    <span class="token comment">// 当用户id为0 且 orderMode为1即热门帖子</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>userId <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> orderMode <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">String</span> cacheKey <span class="token operator">=</span> offset <span class="token operator">+</span> <span class="token string">":"</span> <span class="token operator">+</span> limit<span class="token punctuation">;</span>
        <span class="token comment">// 从本地缓存中获取数据</span>
        <span class="token keyword">return</span> discussPostListCache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 不满足以上条件,则从数据库查数据</span>
    logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"从DB中获取帖子列表数据..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> discussPostMapper<span class="token punctuation">.</span><span class="token function">selectDiscussPosts</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> offset<span class="token punctuation">,</span> limit<span class="token punctuation">,</span> order
<span class="token punctuation">}</span>
                                                
<span class="token comment">/**
 * 根据userid 查询该用户发布的所有帖子数量
 *
 * @param userId 用户id
 * @return
 */</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">findDiscussPostRows</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 当用户id为0时</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>userId <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Integer</span> cacheKey <span class="token operator">=</span> userId<span class="token punctuation">;</span>
        <span class="token comment">// 从本地缓存中获取数据</span>
        <span class="token keyword">return</span> discussPostRowsCache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 不满足以上条件,则从数据库查数据</span>
    logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"从DB中获取帖子数据的总数量..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> discussPostMapper<span class="token punctuation">.</span><span class="token function">selectDiscussPostRows</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="19-4-jemeter-压力测试"><a href="#19-4-jemeter-压力测试" class="headerlink" title="19.4 jemeter 压力测试"></a>19.4 jemeter 压力测试</h3><p>我们使用测试工具，测试缓存是否生效，访问首页的热门帖子：</p>
<p><img src="https://img-blog.csdnimg.cn/20201206135058287.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<p>我们模仿100个线程访问<a href="">http://localhost:8080/community/index?orderMode=1</a> 接口，可以看到控制台只有第一次访问的时候打印sql（从DB中查询数据），其他时候都是走本地缓存获取数据！这样就能提高热点页面访问速度！</p>
<h2 id="20-项目部署"><a href="#20-项目部署" class="headerlink" title="20. 项目部署"></a>20. 项目部署</h2><h3 id="20-1-服务器配置要求-我用的阿里云服务器"><a href="#20-1-服务器配置要求-我用的阿里云服务器" class="headerlink" title="20.1 服务器配置要求(我用的阿里云服务器)"></a>20.1 服务器配置要求(我用的阿里云服务器)</h3><ul>
<li>2核4G(或者2个1核1G)</li>
<li>CentOS 7.X</li>
</ul>
<h3 id="20-2-需要部署的内容"><a href="#20-2-需要部署的内容" class="headerlink" title="20.2 需要部署的内容"></a>20.2 需要部署的内容</h3><ul>
<li>MySQL</li>
<li>Redis</li>
<li>Kafka</li>
<li>ElasticSearch</li>
<li>Wktmltopdf</li>
<li>Nginx</li>
<li>Tomcat</li>
<li>JDK8</li>
<li>项目压缩包</li>
</ul>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/hexo-blog/about" rel="external nofollow noreferrer">兴趣使然の草帽路飞</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://caoshipeng.gitee.io/hexo-blog/hexo-blog/2021/02/05/springboot-fang-niu-ke-lun-tan-xiang-mu-shi-zhan/">https://caoshipeng.gitee.io/hexo-blog/hexo-blog/2021/02/05/springboot-fang-niu-ke-lun-tan-xiang-mu-shi-zhan/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/hexo-blog/about" target="_blank">兴趣使然の草帽路飞</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/hexo-blog/tags/SpringBoot/">
                                    <span class="chip bg-color">SpringBoot</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/hexo-blog/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="qq,qzone,wechat,weibo" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/hexo-blog/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/hexo-blog/medias/reward/alipay.jpg" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/hexo-blog/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    
        <style>
    .valine-card {
        margin: 1.5rem auto;
    }

    .valine-card .card-content {
        padding: 20px 20px 5px 20px;
    }

    #vcomments textarea {
        box-sizing: border-box;
        background: url("/hexo-blog/medias/comment_bg.png") 100% 100% no-repeat;
    }

    #vcomments p {
        margin: 2px 2px 10px;
        font-size: 1.05rem;
        line-height: 1.78rem;
    }

    #vcomments blockquote p {
        text-indent: 0.2rem;
    }

    #vcomments a {
        padding: 0 2px;
        color: #4cbf30;
        font-weight: 500;
        text-decoration: none;
    }

    #vcomments img {
        max-width: 100%;
        height: auto;
        cursor: pointer;
    }

    #vcomments ol li {
        list-style-type: decimal;
    }

    #vcomments ol,
    ul {
        display: block;
        padding-left: 2em;
        word-spacing: 0.05rem;
    }

    #vcomments ul li,
    ol li {
        display: list-item;
        line-height: 1.8rem;
        font-size: 1rem;
    }

    #vcomments ul li {
        list-style-type: disc;
    }

    #vcomments ul ul li {
        list-style-type: circle;
    }

    #vcomments table, th, td {
        padding: 12px 13px;
        border: 1px solid #dfe2e5;
    }

    #vcomments table, th, td {
        border: 0;
    }

    table tr:nth-child(2n), thead {
        background-color: #fafafa;
    }

    #vcomments table th {
        background-color: #f2f2f2;
        min-width: 80px;
    }

    #vcomments table td {
        min-width: 80px;
    }

    #vcomments h1 {
        font-size: 1.85rem;
        font-weight: bold;
        line-height: 2.2rem;
    }

    #vcomments h2 {
        font-size: 1.65rem;
        font-weight: bold;
        line-height: 1.9rem;
    }

    #vcomments h3 {
        font-size: 1.45rem;
        font-weight: bold;
        line-height: 1.7rem;
    }

    #vcomments h4 {
        font-size: 1.25rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    #vcomments h5 {
        font-size: 1.1rem;
        font-weight: bold;
        line-height: 1.4rem;
    }

    #vcomments h6 {
        font-size: 1rem;
        line-height: 1.3rem;
    }

    #vcomments p {
        font-size: 1rem;
        line-height: 1.5rem;
    }

    #vcomments hr {
        margin: 12px 0;
        border: 0;
        border-top: 1px solid #ccc;
    }

    #vcomments blockquote {
        margin: 15px 0;
        border-left: 5px solid #42b983;
        padding: 1rem 0.8rem 0.3rem 0.8rem;
        color: #666;
        background-color: rgba(66, 185, 131, .1);
    }

    #vcomments pre {
        font-family: monospace, monospace;
        padding: 1.2em;
        margin: .5em 0;
        background: #272822;
        overflow: auto;
        border-radius: 0.3em;
        tab-size: 4;
    }

    #vcomments code {
        font-family: monospace, monospace;
        padding: 1px 3px;
        font-size: 0.92rem;
        color: #e96900;
        background-color: #f8f8f8;
        border-radius: 2px;
    }

    #vcomments pre code {
        font-family: monospace, monospace;
        padding: 0;
        color: #e8eaf6;
        background-color: #272822;
    }

    #vcomments pre[class*="language-"] {
        padding: 1.2em;
        margin: .5em 0;
    }

    #vcomments code[class*="language-"],
    pre[class*="language-"] {
        color: #e8eaf6;
    }

    #vcomments [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
        position: inherit;
        margin-left: -1.3rem;
        margin-right: 0.4rem;
        margin-top: -1px;
        vertical-align: middle;
        left: unset;
        visibility: visible;
    }

    #vcomments b,
    strong {
        font-weight: bold;
    }

    #vcomments dfn {
        font-style: italic;
    }

    #vcomments small {
        font-size: 85%;
    }

    #vcomments cite {
        font-style: normal;
    }

    #vcomments mark {
        background-color: #fcf8e3;
        padding: .2em;
    }

    #vcomments table, th, td {
        padding: 12px 13px;
        border: 1px solid #dfe2e5;
    }

    table tr:nth-child(2n), thead {
        background-color: #fafafa;
    }

    #vcomments table th {
        background-color: #f2f2f2;
        min-width: 80px;
    }

    #vcomments table td {
        min-width: 80px;
    }

    #vcomments [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
        position: inherit;
        margin-left: -1.3rem;
        margin-right: 0.4rem;
        margin-top: -1px;
        vertical-align: middle;
        left: unset;
        visibility: visible;
    }
</style>

<div class="card valine-card" data-aos="fade-up">
    <div class="comment_headling" style="font-size: 20px; font-weight: 700; position: relative; padding-left: 20px; top: 15px; padding-bottom: 5px;">
        <i class="fas fa-comments fa-fw" aria-hidden="true"></i>
        <span>评论</span>
    </div>
    <div id="vcomments" class="card-content" style="display: grid">
    </div>
</div>

<script src="/hexo-blog/libs/valine/av-min.js"></script>
<script src="/hexo-blog/libs/valine/Valine.min.js"></script>
<script>
    new Valine({
        el: '#vcomments',
        appId: 'nqtLczfzJWfstaxJjohOkRxK-gzGzoHsz',
        appKey: 'yNBTs2KvEWvNvV5WoiTARROX',
        notify: 'false' === 'true',
        verify: 'false' === 'true',
        visitor: 'true' === 'true',
        avatar: 'mm',
        pageSize: '10',
        lang: 'zh-cn',
        placeholder: 'just go go'
    });
</script>

<!--酷Q推送-->


    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/hexo-blog/2021/02/05/linux-huan-jing-xia-elasticsearch-de-an-zhuang-yu-shi-yong-springboot-zheng-he-yun-fu-wu-qi-shang-de-elasticsearch/">
                    <div class="card-image">
                        
                        
                        <img src="/hexo-blog/medias/featureimages/10.jpg" class="responsive-img" alt="Linux下安装ElasticSearch">
                        
                        <span class="card-title">Linux下安装ElasticSearch</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            Linux下安装ElasticSearch并使用SpringBoot整合
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-02-05
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/hexo-blog/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/" class="post-category">
                                    中间件
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/hexo-blog/tags/ElasticSearch/">
                        <span class="chip bg-color">ElasticSearch</span>
                    </a>
                    
                    <a href="/hexo-blog/tags/Linux/">
                        <span class="chip bg-color">Linux</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/hexo-blog/2021/02/05/hello-world/">
                    <div class="card-image">
                        
                        
                        <img src="/hexo-blog/medias/featureimages/28.jpg" class="responsive-img" alt="Hello World">
                        
                        <span class="card-title">Hello World</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            Hello World测试
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-02-05
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/hexo-blog/categories/%E6%B5%8B%E8%AF%95/" class="post-category">
                                    测试
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/hexo-blog/tags/Hello-World/">
                        <span class="chip bg-color">Hello World</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/hexo-blog/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/hexo-blog/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/hexo-blog/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/hexo-blog/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/hexo-blog/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/hexo-blog/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        font-size: 15px;
        color: #42b983;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="3022496969"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/hexo-blog/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 15px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2021</span>
            
            <span id="year">2021</span>
            <a href="/hexo-blog/about" target="_blank">兴趣使然の草帽路飞</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
            &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                class="white-color">42.7k</span>&nbsp;字
            
            
            
            
            
            
            <span id="busuanzi_container_site_pv">
                |&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;<span id="busuanzi_value_site_pv"
                    class="white-color"></span>&nbsp;次
            </span>
            
            
            <span id="busuanzi_container_site_uv">
                |&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;<span id="busuanzi_value_site_uv"
                    class="white-color"></span>&nbsp;人
            </span>
            
            <br>
            
            <span id="sitetime">载入运行时间...</span>
            <script>
                function siteTime() {
                    var seconds = 1000;
                    var minutes = seconds * 60;
                    var hours = minutes * 60;
                    var days = hours * 24;
                    var years = days * 365;
                    var today = new Date();
                    var startYear = "2021";
                    var startMonth = "2";
                    var startDate = "5";
                    var startHour = "0";
                    var startMinute = "0";
                    var startSecond = "0";
                    var todayYear = today.getFullYear();
                    var todayMonth = today.getMonth() + 1;
                    var todayDate = today.getDate();
                    var todayHour = today.getHours();
                    var todayMinute = today.getMinutes();
                    var todaySecond = today.getSeconds();
                    var t1 = Date.UTC(startYear, startMonth, startDate, startHour, startMinute, startSecond);
                    var t2 = Date.UTC(todayYear, todayMonth, todayDate, todayHour, todayMinute, todaySecond);
                    var diff = t2 - t1;
                    var diffYears = Math.floor(diff / years);
                    var diffDays = Math.floor((diff / days) - diffYears * 365);
                    var diffHours = Math.floor((diff - (diffYears * 365 + diffDays) * days) / hours);
                    var diffMinutes = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours) /
                        minutes);
                    var diffSeconds = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours -
                        diffMinutes * minutes) / seconds);
                    if (startYear == todayYear) {
                        document.getElementById("year").innerHTML = todayYear;
                        document.getElementById("sitetime").innerHTML = "本站已安全运行 " + diffDays + " 天 " + diffHours +
                            " 小时 " + diffMinutes + " 分钟 " + diffSeconds + " 秒";
                    } else {
                        document.getElementById("year").innerHTML = startYear + " - " + todayYear;
                        document.getElementById("sitetime").innerHTML = "本站已安全运行 " + diffYears + " 年 " + diffDays +
                            " 天 " + diffHours + " 小时 " + diffMinutes + " 分钟 " + diffSeconds + " 秒";
                    }
                }
                setInterval(siteTime, 1000);
            </script>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/CodeFarmer1999" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:1165680007@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=1165680007" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 1165680007" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/hexo-blog/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/hexo-blog/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/hexo-blog/libs/materialize/materialize.min.js"></script>
    <script src="/hexo-blog/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/hexo-blog/libs/aos/aos.js"></script>
    <script src="/hexo-blog/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/hexo-blog/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/hexo-blog/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/hexo-blog/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/hexo-blog/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    
    <script type="text/javascript" color="0,0,255"
        pointColor="0,0,255" opacity='0.7'
        zIndex="-1" count="99"
        src="/hexo-blog/libs/background/canvas-nest.js"></script>
    

    
    
    <script type="text/javascript" size="150" alpha='0.6'
        zIndex="-1" src="/hexo-blog/libs/background/ribbon.min.js" async="async"></script>
    

    
    <script type="text/javascript" src="/hexo-blog/libs/background/ribbon-dynamic.js" async="async"></script>
    

    
    <script src="/hexo-blog/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
